---
description: "Turn a rendered analysis document into a Jira story tree: derive stories from the document's own rule ids, check coverage both ways, preview every byte, then create only what does not already exist. Use when an analysis is final and the work needs tickets."
description-tr: "Yazılmış bir analiz dokümanını Jira story ağacına çevirir: story'leri dokümanın kendi kural kimliklerinden türetir, kapsamı iki yönlü kontrol eder, yazılacak her baytı önizler, sonra yalnız var olmayanı açar."
allowed-tools: Bash, Read, AskUserQuestion
argument-hint: "[analysis.md] [--project KEY] [--epic KEY]  -  optional; with no argument, pick from the documents this run emitted"
parameters: [{"name":"document","kind":"path"},{"name":"--project","kind":"text"},{"name":"--epic","kind":"text"}]
gui: form
destructive: false
confirm: none
not-for: create-jira, jira
---

# multi-agent analysis-jira

> **Pickers follow** `$HOME/.claude/multi-agent-refs/picker-contract.md`: never a one-option call, and branch on the option selected, not on its text.

**Input**: $ARGUMENTS

Reads an analysis document as a work breakdown and creates the tree. It never
invents a story: every node comes from an id the document defines.

Contract, severities and reasoning:
`$HOME/.claude/multi-agent-refs/features/analysis-jira.md`.

## Gotchas

- An issue whose label already exists is skipped, never updated. Editing the document and re-running creates only what is missing; existing tickets keep their old text.
- A document with no `BR-`/`FG-` ids still plans, from its `4.N` sub-sections, but its coverage verdict is `unverifiable`: there is nothing to check the tree against.
- An open `EKLENECEK`/`TBD` marker or an open Section 20 row stops planning with exit 4. Resolve them with `/multi-agent:analysis-resolve` first.
- The epic must already exist: stories are linked to it, never an epic created. On Server/Data Center the Epic Link field is discovered from the site; when none is found the stories are created unlinked and the writer says so.
- Channel clones (`issueTree.cloneByChannel`) carry their own labels and are searched like stories, so a re-run never doubles them or their links.
- Story bodies hold only document text. A body warning (no user story, fewer than 2 criteria, no negative criterion) is a gap in the document; fix the document, not the ticket.

## Phase 1 - Plan, offline

```bash
node "$HOME/.claude/scripts/analysis-story-tree.mjs" "<analysis.md>" --json $PAGE > /tmp/ma-plan.json
node "$HOME/.claude/scripts/analysis-story-tree.mjs" "<analysis.md>" $PAGE
```

`$PAGE` is `--page-url <url>` when the document was published (the run's
`outputs.confluencePages[]`); without it the front-matter `confluence_url` is
used, and with neither the story bodies carry no analysis link.

Exit 4 means the document still carries an open placeholder. Stop and report it:
the step is `/multi-agent:analysis-resolve`, and a tree built from an open
question publishes the gap as work somebody is now assigned.

With the quality gates active (autopilot, or `MULTI_AGENT_UNATTENDED=1`), exit 4
also means the spec-consistency check failed: a requirement with no story or no
Test Plan row, or a row that waives a binding constitution rule. Stop and report
the listed ids. Attended, the same check is the advisory `consistency:` line of
the preview and changes nothing else
(`$HOME/.claude/multi-agent-refs/features/constitution.md`).

Exit 2 means nothing could be derived. Say so; do not improvise a tree.

## Phase 2 - Preview, in full

Show the human-readable output verbatim, in `outputLanguage`. It already carries
what makes a preview meaningful:

- every node, its source ids and its identity label
- the coverage verdict **on its own line**, and the consistency verdict below it
- every field beside the pref key it came from, so a wrong setting shows here
  rather than in Jira afterwards
- the write count
- every story's full description, as it will be written, with its body
  warnings; `--brief` gives the one-line-per-node view

Then ask for the epic, once. `AskUserQuestion`:

- **Link to an existing epic** - the user types its key (`--epic <KEY>`)
- **No epic** - the stories are created unlinked

Then the dry run, which is what proves the writer agrees with the plan:

```bash
bash "$HOME/.claude/lib/analysis-jira-write.sh" \
  --plan /tmp/ma-plan.json --project "<KEY>" [--epic "<EPIC>"] --dry-run
```

## Phase 3 - Approve

One `AskUserQuestion`. When the verdict is `ok` or `incomplete`:

- **Create the tree** - proceed
- **Show a node in full** - print one node's body, ask again
- **Cancel** - stop, write nothing

When the verdict is `unverifiable`, the approve option is **replaced**, never
reworded:

- **Create it, unverified** - the tree will be written and recorded as unchecked
- **Show a node in full**
- **Cancel**

A run that could not be checked is allowed. One that looks checked when it was
not is the defect, so the approval has to name it and a plain "Approve" must not
be reachable.

`incomplete` prints its uncovered and invented ids before the question. An
invented id means the plan cites something the document does not define - treat
that as a defect in the plan, not a warning to click past.

Body warnings are printed before the question too. They do not block: the
ticket says only what the document says, and the warning names the gap.

## Phase 4 - Write

```bash
bash "$HOME/.claude/lib/analysis-jira-write.sh" \
  --plan /tmp/ma-plan.json --project "<KEY>" [--epic "<EPIC>"]
```

It searches by label first and skips what exists. Re-running is safe and is the
intended recovery from any failure: the ledger makes a half-written tree
findable rather than duplicable.

**Never pass `--force`-like flags, and never update an existing node.** Jira has
no backup path for fields other than description.

### Write the tickets back

The document lists what it produced. Local and idempotent: the table sits
between `<!-- tickets:start -->` and `<!-- tickets:end -->`, a re-run replaces
it, and only nodes with a key appear.

```bash
LEDGER="$HOME/.claude/logs/multi-agent/_analysis-jira/$(jq -r '.document.id // "unidentified"' /tmp/ma-plan.json).jsonl"
node "$HOME/.claude/scripts/analysis-tickets-writeback.mjs" \
  --doc "<analysis.md>" --ledger "$LEDGER" --plan /tmp/ma-plan.json
```

When the document has a Confluence page, updating it is a **separate**
`AskUserQuestion`, never part of the tree approval:

- **Update the Confluence page** - publish the document with its new table
- **Keep it local** - the page stays as it is

```bash
python3 "$HOME/.claude/lib/md2confluence-v3.py" update \
  --page-id "<pageId>" --title "<page title>" \
  --markdown "<analysis.md>" --attachments-dir "$(dirname "<analysis.md>")"
```

Read its JSON envelope as the analysis render step does, and surface any
missing-attachment warning.

## Phase 5 - Report

Keys created, keys skipped, the epic linked (or none), the coverage verdict, and the ledger path. If the
verdict was `unverifiable`, say that in the report too - not only at approval
time, because the report is what gets pasted elsewhere.

**Stop. No worktree, no branch, no dev chain.**
