feat(MAPCO-11431): claim a ticket and release it, with nothing in between - #6
Open
razbroc wants to merge 2 commits into
Open
feat(MAPCO-11431): claim a ticket and release it, with nothing in between#6razbroc wants to merge 2 commits into
razbroc wants to merge 2 commits into
Conversation
Walks the whole Jira state machine with an empty middle: take the oldest ready ticket, assign the bot, move it to In Progress, then comment, return it to Open and unassign. Claiming is optimistic because Jira is the only state store. After writing the assignee the worker re-reads the issue, and a name that is not its own means a human got there first: back off, write nothing further, and do not clear the field — that would take the ticket off them. Release runs comment, transition, unassign, in that order. Unassigning is what makes a ticket visible to the poll query again, so it goes last: a failure part-way through leaves the ticket held and In Progress, which the query skips and the boot-time sweep recovers. Unassigning first risks leaving a ticket that polls straight back in and gets commented on every cycle. Transitions are matched on their target status rather than their own name, because transition names are verbs on a real workflow (Start Progress). Both jira_get_transitions and expand=transitions are rejected by the write-pilot MCP server, so the actual vocabulary could not be verified the way the poll query was; a no-transition refusal logs the names it was offered, so the first real run reports them instead of refusing every ticket in silence. The bot's identity is configured rather than discovered. The MCP server runs under a shared service account with no per-user attribution, and Jira takes an identifier on write but returns a surname-first display name on read, so both halves are required and neither can be derived from the other. Refs: MAPCO-11431
|
🎫 Related Jira Issue: MAPCO-11431 |
The secrets-context fallback in 908f19a still resolved to an empty input, so the action kept failing with 'Input required and not supplied: repo-token' — neither GH_PAT nor secrets.GITHUB_TOKEN came through. github.token is always populated, and the job already holds the pull-requests: write permission. This only takes effect for pull requests whose base branch carries it, because pull_request_target resolves the workflow from the base. Refs: MAPCO-11431
This was referenced Aug 27, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #5 — review that first, and this PR retargets to
masteronce it merges.Walks the whole Jira state machine with an empty middle: take the oldest ready ticket, assign the bot, move it to In Progress, then comment, return it to Open and unassign. No branch, no changes, no PR yet.
Claiming is optimistic
Jira is the only state store, so there is no lock to take. The worker writes the assignee and then re-reads the issue; a name that is not its own means a human got there first, so it backs off, writes nothing further, and deliberately does not clear the field — that would take the ticket off them.
The In Progress transition is looked up before any write. A workflow with no route in means the ticket can never be worked, and that is a clean refusal rather than a ticket held by a bot that cannot start it.
Release order is deliberate
Comment → transition to Open → unassign last, which is the reverse of how it reads naturally.
Unassigning is what makes a ticket visible to the poll query again (it filters
assignee is EMPTY), so it goes last. A failure part-way through then leaves the ticket held by the bot and In Progress — which the query skips and the boot-time orphan sweep (MAPCO-11432) recovers. Unassigning first would risk leaving a ticket unassigned and In Progress, which polls straight back in and gets commented on every single cycle.Transitions are matched on their target status, not their own name, because transition names are verbs on a real workflow (
Start Progress, notIn Progress). Matching by name alone would have refused every ticket and made this a silent no-op in production.Both
jira_get_transitionsandexpand=transitionsare rejected by the write-pilot MCP server, so the real MAPCO vocabulary could not be read the way the poll query was verified in MAPCO-11427. The lookup handles both shapes (target status, name as fallback), and ano-transitionrefusal logs theofferednames — so the first real run reports the vocabulary instead of refusing in silence. Confirm it from that log line before trusting a deployment.Bot identity is configured, not discovered
Two new required env vars,
JIRA_BOT_ACCOUNTandJIRA_BOT_DISPLAY_NAME. They look redundant and are not: the MCP server runs under a shared service account so the worker cannot ask Jira who it is, and Jira takes an identifier on write but returns a surname-first display name on read. Neither is derivable from the other, and setting them inconsistently makes every claim read as lost.Acceptance criteria
61 tests pass;
claim.ts,cycle.tsandworkerConfig.tsare at 100% line coverage.Refs: MAPCO-11431