Skip to content

feat(MAPCO-11436): worker builds the branch, commit and PR in code - #10

Open
razbroc wants to merge 1 commit into
feat/count-attemptsfrom
feat/branch-commit-pr
Open

feat(MAPCO-11436): worker builds the branch, commit and PR in code#10
razbroc wants to merge 1 commit into
feat/count-attemptsfrom
feat/branch-commit-pr

Conversation

@razbroc

@razbroc razbroc commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Stacked on #9 — review that first, and this PR retargets as the stack merges.

Question Answer
Bug fix
New feature
Breaking change
Deprecations
Documentation
Tests added
Chore

The output the mechanism exists for. Once a verified diff is in the working tree, the worker itself commits it, pushes a branch and opens a PR.

This is worker code, not agent instructions. The model never runs git, never sees a token, and is never asked to follow the naming rules — the worker computes the branch name and the commit title from the Jira issue and writes them. These constraints are only real if code enforces them; a prompt that says "never push to master" enforces nothing.

Naming is derived, not requested

Branch is agent/{type}/MAPCO-XXXXX-short-slug, with the agent/ segment leftmost so agent branches stay greppable and can be protected against later. The slug comes from the feature title, not the repo prefix — a ticket summary is <repo-name>: <feature title> and only the part before the first colon is the repo name, so resolveRepo's existing split is reused rather than duplicated.

Slugification is where this kind of code usually breaks, so it is tested against summaries that are pure punctuation, 400 characters long, unicode, already containing slashes, ending in a dot, and ending in .lock.

⚠️ A Bug becomes fix:, not bug:

The ticket says the type is feat, bug or chore. bug is not in @map-colonies/commitlint-config's type-enum — I confirmed that against the installed package — so a bug: subject would fail this repo's own commit hook. The mapping is therefore { feat, bug → fix, chore }, and the ticket's wording predates checking the org config.

Titles are not flattened to chore:. Around 109 MapColonies repos run release-please, so a merged feat: will cut a release. That is accepted — an agent-authored feature is a feature.

Verified rather than asserted: 101 generated commit messages (23 hostile summaries plus the full 78-case type × shape cross-product) were run through the real commitlint --edit against the org config. Zero failures, including emoji, Hebrew, Japanese, all-caps first words, trailing full stops and BREAKING CHANGE: subjects. The issue key sits in a trailing (KEY) reference because a leading key trips subject-case.

Pushing to master is structurally impossible

Not discouraged — impossible. assertWritable rejects the default branch as a push target before a token is minted, and CliGit has no force, no delete, no merge and no approve method to call. Tested against a real bare remote with hostile hooks.

The token never enters argv: it goes through a git credential helper, and that is proven by handing the real snippet to the real git credential fill rather than by string equality.

Acceptance criteria

  • The worker commits and pushes; the model has no git or GitHub capability at any point
  • Branch name and commit title are derived in code from the Jira issue type, not produced by the model
  • Titles are conventional commits using the real type, not flattened to chore: (see the bugfix note)
  • The PR is opened as a normal PR, body links the ticket and states what was verified locally
  • No reviewer and no assignee is set on the PR
  • Installation tokens are minted per run, never a static long-lived token. The per-call, never-cached contract is enforced by TokenProvider, but nothing implements it — App JWT signing plus POST /app/installations/{id}/access_tokens needs the GitHub App from MAPCO-11428.
  • Partial — Pushing to master, merging and approving are attempted in a scratch repo and observed to fail. Push-to-master is properly attempted against a real bare remote and observed to fail. Merge/approve is only "the method does not exist"; observing GitHub's own refusal needs the App.
  • The Jira ticket gets a comment linking the PR

Known sharp edges

  • A retry after a partial publish can never succeed. branchName is deterministic per ticket and push is a plain non-forced refs/heads/X:refs/heads/X with no fetch or rebase, so a ticket whose first attempt pushed and then failed at POST /pulls gets rejected non-fast-forward on the second attempt and burns it. Confirmed against real git.
  • In the only mode reachable today every changed path goes into one git add argv, which is an E2BIG risk on a clone whose test script leaves a large un-gitignored tree.
  • maintainer_can_modify: true has not been exercised against the live API for a same-repo head branch.
  • git status --porcelain is parsed by byte offset — correct for the default format, wrong for a path containing a quote or newline. Fine for the emptiness check it feeds; don't build on it.

Not wired in

publishPullRequest has no caller. There is no clone step, no TokenProvider and no source of GitIdentity to wire it with.

Refs: MAPCO-11436

MAPCO-11436. The worker derives the branch name and the conventional-commit
title in code from the Jira issue type and does the git and GitHub work itself.
The model never runs git, never sees a token and is never asked to follow the
naming rules.

Branches are agent/{type}/MAPCO-XXXXX-slug with the agent/ segment leftmost so
they stay greppable and can be protected later. Titles use the real type rather
than being flattened to chore:, so a merged feat: cuts a release — an
agent-authored feature is a feature. A Bug maps to fix:, not bug:, because bug
is absent from @map-colonies/commitlint-config's type-enum and would fail the
repo's own commit hook.

Pushing to master is rejected structurally: the default branch is refused as a
push target before a token is minted, and there is no force, delete, merge or
approve method to call. Verified against a real bare remote with hostile hooks.

`TokenProvider` has no implementation — per-run installation tokens need the
GitHub App from MAPCO-11428. Not wired into runCycle, and nothing clones yet.
@github-actions

Copy link
Copy Markdown

🎫 Related Jira Issue: MAPCO-11436

@razbroc razbroc self-assigned this Aug 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant