Repository navigation
Description
Problem
The squash message must pass the repository's lint against dictionaries from the pull request head, not from whichever branch the operator has checked out. Today lint-squash-msg.sh (37 lines) finds the pull request, reads its head, and calls ma_lint in merge-agent.sh (about 45 lines), which fetches the pinned commit, copies .cspell.jsonc and .cspell-words.txt out of it into a temporary directory, and runs either mise run lint-squash-msg or the configured lint_squash_cmd. Review and merge both call it. It is under the shell freeze in #588.
Part of #324, within #588. Child 06 in #324's Children list. Replaces packages/agents/source/skills/merge-pr/shared/scripts/lint-squash-msg.sh and the lint function of packages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh.
Acceptance criteria
- AC1: Given a pull request number, or a
SQUASH_AGENTMSGsubject ending in(#<number>), whenagentrepo merge lintruns, then it lints against the dictionaries at the pull request's head and exits with the lint command's status. - AC2: Given no number and a subject without
(#<number>), or a head that is not a full 40-character commit, when the command runs, then it exits 1 with the same message as the shell script. - AC3: Given the head carries
.cspell.jsoncor.cspell-words.txt, when the lint runs, then those head copies are used and removed afterwards; given the head lacks them, then the lint runs without them and any inheritedDEVTOOLS_CSPELL_CONFIGis dropped. - AC4: Given the pinned head commit is not in the object store and cannot be fetched, when the command runs, then it exits 1 with
Could not fetch the pinned pull request head.; given the commit is present but a dictionary file cannot be extracted from it, then it exits 1 withCould not read <file> from the pull request head.(the file exists in the head but its extraction fails, as intests/skills/merge-pr/scripts/merge-workflow.bats:277; a head with no dictionary is the successful optional case of AC3); the fetch moves no branch. - AC5: Given unattended mode, when the command runs, then it runs the repository's
lint_squash_cmd(defaultmise run lint-squash-msg) and refuses an empty value; given attended mode, then it runsmise run lint-squash-msg. - AC6: Given a successful lint, a failing lint, a configuration refusal, and a dictionary-read failure, when the command ends, then the temporary directory is gone in every case.
- AC7: Non-functional: the lint behavior is reusable by later commands, so that a second caller gets the same result as
agentrepo merge lint, and the command runs on macOS, Linux and Windows in CI. - AC8: Given a divergent checkout, when the command runs, then
lint_squash_cmdcomes from the pinned base through Read gate settings from the pinned base in Go #980's reader, a checkout value cannot replace or suppress it, and an empty base value refuses.
Scope and non-goals
Scope: agentrepo merge lint and the shared lint behavior the review and merge commands use, with tests ported from the lint cases in merge-workflow.bats and policy.bats.
Non-goal: the commit-msg rules themselves, which stay in commit-lint and mise. Non-goal: editing the shell scripts before child 14.
Approach
Meet AC1 to AC8 with failing cases first, using a fake mise and a scratch repository whose head carries dictionary files, and compare the shell script's output on the same fixtures. Mechanism is the implementer's choice.
Dependencies
Prerequisites: #321 (repository configuration reader), #333 and #980 (pinned-base settings reader).
Size
S. One pull request.
Verify plan
- AC1, AC2: fake-
ghtable cases comparing messages and statuses with the shell script. - AC3, AC4: scratch repositories with and without dictionaries, one with an absent unfetchable commit, one with a present commit lacking a dictionary (success) and one with an existing dictionary whose extraction fails, asserting what the lint saw, each message and the cleanup.
- AC5: stub
miseand a configuredlint_squash_cmd, including the empty value. - AC6: a test per exit path asserting the temporary directory is gone.
- AC7: a test that invokes the shared lint behavior a second way (not through the command) and gets the same result as the command; the CI matrix run. The review and merge integration checks belong to children 09 and 10.
- AC8: a scratch repository whose checkout
.agents/agent-skills.confsets or blankslint_squash_cmddifferently from the base, asserting the base command runs, the checkout value neither replaces nor suppresses it, and an empty base value refuses. - 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
Linting against the wrong dictionaries would pass or fail a message for the wrong reasons. AC3 pins the head copies. Undo: revert; the shell script is untouched.
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 — The squash message lint runs from agentrepo merge
Model: gpt-6-astra
Child 06 The squash message lint runs from agentrepo merge
Verdict: READY
Checked: The extraction-failure fixture now uses an existing dictionary whose extraction fails, matching
tests/skills/merge-pr/scripts/merge-workflow.bats:277. AC7 can be verified before downstream commands exist, with integration assigned to children 09 and 10. Fetch errors, optional dictionaries and cleanup matchpackages/agents/source/skills/merge-pr/shared/scripts/merge-agent.sh:32.Gaps: None.
Split: None needed.
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