--- name: merge-jira-postmortem description: "Post structured post-merge comment to Jira ticket + transition to Done (skip transition in blocked mode). Mandatory even on 0-issue PRs. Triggers: jira postmortem, comment jira, /jira-postmortem." --- # merge-jira-postmortem ## Host execution **Claude Code:** retain the agent-dispatch and concurrency behavior defined below. **Codex:** use only the inline behavior stated here. On Codex this sub-skill runs inline under `agile-11-merge-train` with `concurrency=0`; never spawn or assume a named agent. Perform its full gate and return its normal receipt to the caller. ## Purpose Post a structured post-merge findings comment to a Jira ticket, synthesised from this session's review and fix work, and — when the PR merged — transition the ticket to **Done**. In `blocked` mode, post the block-notice comment and leave the ticket state untouched. **Mandatory even on a clean PR.** A 0-issue PR still gets the comment and the transition; "What was correct" becomes the whole body. Skipping because "nothing went wrong" strands the ticket in its in-review column and breaks the merge-train contract. ## Input Jira key from args (`ABC-123`), else inferred from the branch name. Optional mode: `merged` (default) or `blocked`. **`conflict_map` entry** — `agile-11-merge-train` 3g passes this PR's Phase-1 entry verbatim: ``` conflict_map entry: pr: ticket: collisions: - file: with_pr: with_ticket: kind: append | same-lines ``` `collisions: []` is a real value meaning "checked, none" — not "not supplied". Every collision becomes a Cross-PR bullet **and** an entry in the `collisions recorded` receipt field. Never invent one the caller did not pass; never silently drop one it did. Invoked standalone with no entry, derive the collisions yourself and say so. **Config** (consumer repo `CLAUDE.md` / `AGENTS.md`): `cloudId` — required, no default. `ticket-prefix-regex` — default `[A-Z]+-\d+`. ## Steps 1. **Gather from session context:** every issue found during review; every fix applied and why; what was already correct; AC-by-AC verification (satisfied / not, and why); **conscious accepts** (each deliberate DoD deviation — what the DoD asks, what was done instead, why the convention wins, where the equivalent-strength coverage lives, and that it was deliberate); **cross-PR conflicts from the caller's entry, not from recollection**. 2. **Post the comment** via `mcp__atlassian__addCommentToJiraIssue` (configured `cloudId`, `contentFormat: markdown`) and **capture the returned comment id** — it is the proof it was posted. It **opens with `🤖 `**: this comment is the ticket's only record that the merge path ran, and the audit gates read the marker, not the prose. 3. **`merged` mode → transition to Done.** `mcp__atlassian__getTransitionsForJiraIssue`, find the transition whose target status category is `done` / colorName `green`, call `mcp__atlassian__transitionJiraIssue`. (Fast path: if the repo declares a stable `done-transition-id`, call it directly and fall back to the lookup on failure.) **Then read the status back** with `mcp__atlassian__getJiraIssue` and confirm the category is `done` — a transition call that returned without the ticket landing in a done-category status is not complete. 4. **`blocked` mode → do not transition.** The PR stays open with a block comment and the ticket stays in its column. 5. **Return the receipt.** `agile-11-merge-train` 3g verifies it before counting the PR done, and its Phase 5 re-dispatches this skill for any merged PR whose ticket is not done-category. `collisions recorded` echoes exactly what you wrote into the comment — that echo is how the caller proves the Phase-1 conflict map reached the ticket instead of evaporating in the hand-off. ``` Postmortem receipt: mode: merged | blocked comment id: marker: post_merge posted status: (category: ) collisions recorded: @, @ | none ``` ## Comment structure Every issue gets its own numbered section with root cause, fix, and a **generalizable** lesson ("always use X pattern when Y", never "fix this specific file"). Be specific — file names, line numbers, function names. The comment is a permanent ticket artifact read by humans during retro and future incident investigations, so write full sentences in normal English, and **never omit "What was correct"**, however many issues there were. ```markdown 🤖 ## Post-merge review findings — what was wrong issue(s) found during PR review, fixed before merge. ### . : **Root cause:** **Fix:** **Lesson:** ### What was correct - ### Conscious accepts (if any) - **DoD asks:** — **done instead:** — **why:** — **equivalent coverage:** ``. Deliberate decision, not an oversight. ### Cross-PR conflicts (if any) - Conflicted with **#** () on ``. The two tickets should be linked in Jira (``) — the missing link is why the overlap was only discovered at merge time. ``` On a 0-issue PR, open with "0 issues found during PR review." and go straight to "What was correct" plus any cross-PR conflicts. **Block mode:** ```markdown 🤖 ## PR blocked — not merged **Reason:** ### Missing / wrong - AC: — ### What was correct - ### Path forward - ``` **Severity:** **Critical** — would cause a runtime error, data corruption, test failure, security issue, or autogenerate drift. **Minor** — misleading docs, a wrong port in a docstring, a missing run command, a stale AC description. ## Boundaries - **Cross-PR conflict ≠ Jira link creation.** This skill records the recommendation; `agile-11-merge-train` **3g** creates the link via `mcp__atlassian__createIssueLink`, in the same step that dispatches this skill. Never call `mcp__atlassian__createIssueLink` from here. - **3g confirms the link inline; Phase 4 reconciles.** After creating one, the train appends `Jira link created: relates to .` to the most recent postmortem on each side — or the failure reason if it could not. Its Phase 4 then walks the whole conflict map and creates any pair 3g could not reach (a collision whose other side had not merged yet, or a call that failed). That closes the loop so a later reader sees the link was applied, not merely recommended.