@mmerterden/multi-agent-pipeline 10.8.0 → 10.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/README.md +3 -1
  3. package/docs/engineering.md +76 -0
  4. package/docs/features.md +40 -36
  5. package/package.json +1 -1
  6. package/pipeline/commands/multi-agent/channels.md +42 -6
  7. package/pipeline/commands/multi-agent/finish.md +15 -6
  8. package/pipeline/commands/multi-agent/generate-bug.md +33 -0
  9. package/pipeline/commands/multi-agent/generate-task.md +33 -0
  10. package/pipeline/commands/multi-agent/help.md +12 -0
  11. package/pipeline/commands/multi-agent/manual-test.md +9 -2
  12. package/pipeline/commands/multi-agent/refs/channels/pr.md +1 -1
  13. package/pipeline/commands/multi-agent/refs/cross-cli-contract.md +7 -6
  14. package/pipeline/commands/multi-agent/refs/generate-issue.md +197 -0
  15. package/pipeline/commands/multi-agent/refs/keychain.md +12 -0
  16. package/pipeline/commands/multi-agent/refs/phases/phase-0-init.md +40 -2
  17. package/pipeline/commands/multi-agent/refs/phases/phase-3-dev.md +12 -0
  18. package/pipeline/commands/multi-agent/refs/phases/phase-4-review.md +4 -23
  19. package/pipeline/commands/multi-agent/refs/phases/phase-5-test.md +6 -1
  20. package/pipeline/commands/multi-agent/refs/phases/phase-7-report.md +5 -1
  21. package/pipeline/commands/multi-agent/refs/progress-contract.md +1 -0
  22. package/pipeline/commands/multi-agent/refs/tracker-contract.md +56 -13
  23. package/pipeline/commands/multi-agent/resume.md +6 -2
  24. package/pipeline/commands/multi-agent/sync.md +5 -5
  25. package/pipeline/commands/multi-agent.md +4 -0
  26. package/pipeline/lib/figma-mcp-refresh.sh +79 -0
  27. package/pipeline/preferences-template.json +2 -1
  28. package/pipeline/schemas/prefs.schema.json +35 -0
  29. package/pipeline/schemas/token-budget.json +7 -7
  30. package/pipeline/scripts/README.md +1 -0
  31. package/pipeline/scripts/fixtures/install-layout.tsv +6 -6
  32. package/pipeline/scripts/phase-tracker.sh +134 -22
  33. package/pipeline/scripts/smoke-channels-approval-gate.sh +60 -0
  34. package/pipeline/scripts/smoke-generate-issue.sh +114 -0
  35. package/pipeline/scripts/smoke-phase-tracker.sh +69 -0
  36. package/pipeline/scripts/smoke-progress-contract.sh +9 -0
  37. package/pipeline/scripts/smoke-tasklist-ordering.sh +1 -0
  38. package/pipeline/scripts/smoke-token-preflight.sh +82 -0
  39. package/pipeline/scripts/smoke-tracker-contract.sh +62 -0
  40. package/pipeline/scripts/smoke-update-check.sh +122 -0
  41. package/pipeline/scripts/update-check.sh +82 -0
  42. package/pipeline/skills/.skills-index.json +22 -4
  43. package/pipeline/skills/shared/core/multi-agent/SKILL.md +2 -1
  44. package/pipeline/skills/shared/core/multi-agent-channels/SKILL.md +4 -2
  45. package/pipeline/skills/shared/core/multi-agent-generate-bug/SKILL.md +39 -0
  46. package/pipeline/skills/shared/core/multi-agent-generate-task/SKILL.md +39 -0
  47. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +4 -0
  48. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +5 -5
  49. package/pipeline/skills/skills-index.md +5 -3
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: "Create a standards-compliant Jira Bug: mines project conventions, drafts in outputLanguage, full preview + explicit approval before create."
3
+ argument-hint: "[\"<free-text description>\"] [figma-url] - both optional; pasted logs/screens in the text land in Steps to Reproduce / Environment"
4
+ ---
5
+
6
+ # multi-agent generate-bug - Standards-Compliant Jira Bug Creator
7
+
8
+ **Input**: $ARGUMENTS
9
+
10
+ Creates exactly one Jira **Bug**, and only after explicit approval. No branches, no commits, no worktrees, no pipeline chaining. The draft learns the target project's conventions from its recent Bugs (summary format, description template, labels, components, priority norms) and offers active-sprint placement when a sprint is running.
11
+
12
+ > **Language**: instruction prose here is English. AskUserQuestion `question`/`description` and the issue content (summary + description) follow `prefs.global.outputLanguage` - an intentional exception to the "external payloads stay English" default, because the issue is authored for the user's team. `label`/`header` stay English.
13
+
14
+ ## Profile
15
+
16
+ | Key | Value |
17
+ |---|---|
18
+ | `ISSUE_TYPE` | `Bug` |
19
+ | Default description sections | Steps to Reproduce, Expected Result, Actual Result, Environment, Design Reference (only when a Figma URL is given), Notes |
20
+ | JQL sample filter | `issuetype = Bug` |
21
+ | Priority default | mined norm from sampled Bugs (bug priorities often skew higher - respect the project's own norm) |
22
+
23
+ ## Flow
24
+
25
+ Read `$HOME/.claude/commands/multi-agent/refs/generate-issue.md` and execute the 11-step shared flow with the profile above. Non-negotiables restated:
26
+
27
+ - Free-text parsing maps logs, stack traces, and device/OS mentions into Steps to Reproduce and Environment; anything underivable is asked in step [7/11], never invented.
28
+ - Ask the user (AskUserQuestion) about every genuinely unknown field - component, epic, priority, labels, assignee, sprint vs backlog, required custom fields, missing Steps to Reproduce / Environment.
29
+ - Step [8/11] full preview + approval gate always runs. `Approve` / `Edit` (loop) / `Cancel`. No bypass exists.
30
+
31
+ ## Error paths
32
+
33
+ See `refs/generate-issue.md` Error paths. No command-specific additions.
@@ -0,0 +1,33 @@
1
+ ---
2
+ description: "Create a standards-compliant Jira Task: mines project conventions, drafts in outputLanguage, full preview + explicit approval before create."
3
+ argument-hint: "[\"<free-text description>\"] [figma-url] - both optional, asked interactively when missing"
4
+ ---
5
+
6
+ # multi-agent generate-task - Standards-Compliant Jira Task Creator
7
+
8
+ **Input**: $ARGUMENTS
9
+
10
+ Creates exactly one Jira **Task**, and only after explicit approval. No branches, no commits, no worktrees, no pipeline chaining. The draft learns the target project's conventions from its recent Tasks (summary format, description template, labels, components, priority norms) and offers active-sprint placement when a sprint is running.
11
+
12
+ > **Language**: instruction prose here is English. AskUserQuestion `question`/`description` and the issue content (summary + description) follow `prefs.global.outputLanguage` - an intentional exception to the "external payloads stay English" default, because the issue is authored for the user's team. `label`/`header` stay English.
13
+
14
+ ## Profile
15
+
16
+ | Key | Value |
17
+ |---|---|
18
+ | `ISSUE_TYPE` | `Task` |
19
+ | Default description sections | Goal, Scope, Acceptance Criteria, Design Reference (only when a Figma URL is given), Notes |
20
+ | JQL sample filter | `issuetype = Task` |
21
+ | Priority default | mined norm from sampled Tasks |
22
+
23
+ ## Flow
24
+
25
+ Read `$HOME/.claude/commands/multi-agent/refs/generate-issue.md` and execute the 11-step shared flow with the profile above. Non-negotiables restated:
26
+
27
+ - Ask the user (AskUserQuestion) about every genuinely unknown field - component, epic, priority, labels, assignee, sprint vs backlog, required custom fields.
28
+ - Step [8/11] full preview + approval gate always runs. `Approve` / `Edit` (loop) / `Cancel`. No bypass exists.
29
+ - Never invent Goal, Scope, or Acceptance Criteria content the user did not supply.
30
+
31
+ ## Error paths
32
+
33
+ See `refs/generate-issue.md` Error paths. No command-specific additions.
@@ -111,6 +111,8 @@ Post-Hoc & Side-Channel:
111
111
  /multi-agent:analysis ["analysis-name"] Feature-spec analysis (Figma + Swagger + Confluence + repos) → per-platform v3 doc (23-section Full / 7-section Lite)
112
112
  /multi-agent:analysis-resolve [doc] Resolve Section 20 open questions of an analysis doc, one at a time with source-labeled candidates
113
113
  /multi-agent:build-optimize iOS-only Xcode build perf wrapper → benchmark + analyze + recommend-first .build-benchmark/optimization-plan.md
114
+ /multi-agent:generate-task ["desc"] [figma-url] Create a Jira Task matching team conventions (mining + active sprint + preview & approval)
115
+ /multi-agent:generate-bug ["desc"] [figma-url] Create a Jira Bug matching team conventions (mining + active sprint + preview & approval)
114
116
  /multi-agent:diff-explain Map a Phase 4 triage finding back to specific diff lines
115
117
  /multi-agent:search Cross-task log search with smart ranking; --semantic queries triage corpus
116
118
  /multi-agent:scan Skill security scan against tiered pattern catalog
@@ -220,6 +222,10 @@ Examples:
220
222
  # Review current diff only
221
223
  /multi-agent:review
222
224
 
225
+ # Create a Jira issue that matches team conventions (preview + approval before create)
226
+ /multi-agent:generate-task "Profile screen empty state" https://figma.com/design/abc?node-id=1-2
227
+ /multi-agent:generate-bug "Login crash on iOS 17, see attached log"
228
+
223
229
  ------------------------------------------------------------
224
230
 
225
231
  Logs: $HOME/.claude/logs/multi-agent/{project}/{task-id}/
@@ -318,6 +324,8 @@ Post-Hoc & Side-Channel:
318
324
  /multi-agent:analysis ["analysis-name"] Feature-spec analizi (Figma + Swagger + Confluence + repolar) → platform başına v3 doküman (23 bölüm Full / 7 bölüm Lite)
319
325
  /multi-agent:analysis-resolve [doc] Analiz dokümanının Bölüm 20 açık sorularını kaynak etiketli adaylarla teker teker çözer
320
326
  /multi-agent:build-optimize iOS-only Xcode build performance wrapper → benchmark + analiz + recommend-first .build-benchmark/optimization-plan.md
327
+ /multi-agent:generate-task ["açıklama"] [figma-url] Takım standartlarına uygun Jira Task oluştur (convention mining + aktif sprint + önizleme & onay)
328
+ /multi-agent:generate-bug ["açıklama"] [figma-url] Takım standartlarına uygun Jira Bug oluştur (convention mining + aktif sprint + önizleme & onay)
321
329
  /multi-agent:diff-explain Phase 4 triage bulgusunu diff satırlarına eşle
322
330
  /multi-agent:search Task log'larında akıllı arama; --semantic triage corpus'unu sorgular
323
331
  /multi-agent:scan Skill güvenlik taraması (tiered pattern catalog)
@@ -427,6 +435,10 @@ Quality & Telemetry (advisory, default açık - prefs.global.* ile kapatılabi
427
435
  # Sadece mevcut diff'i review et
428
436
  /multi-agent:review
429
437
 
438
+ # Takım standartlarına uygun Jira issue oluştur (oluşturmadan önce önizleme + onay)
439
+ /multi-agent:generate-task "Profil ekranı empty state" https://figma.com/design/abc?node-id=1-2
440
+ /multi-agent:generate-bug "iOS 17'de login crash, log ekte"
441
+
430
442
  ------------------------------------------------------------
431
443
 
432
444
  Log'lar: $HOME/.claude/logs/multi-agent/{project}/{task-id}/
@@ -22,6 +22,13 @@ Lets you switch to the task branch for manual testing in Xcode before the PR is
22
22
  git checkout {branch-name}
23
23
  ```
24
24
 
25
+ Then mark the tracker as waiting (this CONTINUES the task's existing `tracker-state.json`; never `init` here - see `refs/tracker-contract.md` "Continuation runs"). On Claude Code in a fresh session, first rebuild the TaskList from state per the same contract:
26
+ ```bash
27
+ bash $HOME/.claude/scripts/phase-tracker.sh update 5 in_progress
28
+ bash $HOME/.claude/scripts/phase-tracker.sh now 5 "awaiting local test (user)"
29
+ bash $HOME/.claude/scripts/phase-tracker.sh render
30
+ ```
31
+
25
32
  4. **Tell the user how to test**:
26
33
  ```
27
34
  🧪 Switched to branch: {branch-name}
@@ -39,5 +46,5 @@ Lets you switch to the task branch for manual testing in Xcode before the PR is
39
46
  5. **Wait for the user's reply**
40
47
 
41
48
  6. **Branch on the answer**:
42
- - **OK** → recreate the worktree, continue to Phase 6
43
- - **Fix needed** → recreate the worktree, apply the fix
49
+ - **OK** → `phase-tracker.sh update 5 completed` + `phase-tracker.sh meta 5 Result "local test passed (user)"`, recreate the worktree, continue to Phase 6
50
+ - **Fix needed** → `phase-tracker.sh now 5 "applying fix: <summary>"`, recreate the worktree, apply the fix
@@ -120,7 +120,7 @@ Single-repo tasks return one entry from `channels-multi-repo.sh targets ...` wit
120
120
  The Bitbucket REST API returns `409 Conflict` if `version` is stale. Adapter behaviour:
121
121
 
122
122
  1. Refetch PR JSON, retry the PUT once with the new `version`.
123
- 2. Second mismatch → fail this adapter, log reason, return `{status: "failed", reason: "version conflict"}`. Other adapters keep running - non-blocking by Step 6 contract.
123
+ 2. Second mismatch → fail this adapter, log reason, return `{status: "failed", reason: "version conflict"}`. Other adapters keep running - non-blocking by Step 7 contract.
124
124
 
125
125
  ## Flags that affect this adapter
126
126
 
@@ -6,19 +6,20 @@
6
6
 
7
7
  ---
8
8
 
9
- ## 1. Command Inventory (35 commands)
9
+ ## 1. Command Inventory (37 commands)
10
10
 
11
11
  ```
12
12
  analysis, analysis-resolve, autopilot, build-optimize, channels, delete, dev,
13
13
  dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, garbage-collect,
14
- help, issue, jira, kill, language, local, local-autopilot, log, manual-test,
15
- prune-logs, purge, refactor, resume, review, scan, search, setup, stack, status,
16
- sync, test, update
14
+ generate-bug, generate-task, help, issue, jira, kill, language, local,
15
+ local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review,
16
+ scan, search, setup, stack, status, sync, test, update
17
17
  ```
18
18
 
19
19
  Categories:
20
20
 
21
21
  - **Interactive pickers** (single-purpose, not modes): `jira`, `issue`
22
+ - **Issue generators** (one-shot, no worktree, hard approval gate before create): `generate-task`, `generate-bug`
22
23
  - **Full 8-phase modes**: `autopilot`, `local`, `local-autopilot`
23
24
  - **Fast modes** (Init -> Dev(Opus) -> Commit -> Report): `dev`, `dev-autopilot`, `dev-local`, `dev-local-autopilot`
24
25
  - **Tail modes** (run the pipeline tail over already-done local work): `finish`
@@ -29,7 +30,7 @@ Categories:
29
30
 
30
31
  ### 1.1 Figma component subphase skills
31
32
 
32
- In addition to the 35 top-level multi-agent commands, the figma-to-component pipeline ships platform-specific skills that multi-agent dispatches from Phase 3 (see `refs/component-dispatch.md`). The structure is **platform-parallel iOS + Android with a shared common pool**:
33
+ In addition to the 37 top-level multi-agent commands, the figma-to-component pipeline ships platform-specific skills that multi-agent dispatches from Phase 3 (see `refs/component-dispatch.md`). The structure is **platform-parallel iOS + Android with a shared common pool**:
33
34
 
34
35
  | Location | Skill count | Purpose |
35
36
  |---|---|---|
@@ -311,7 +312,7 @@ For clipboard ops, callers still gate with `if command -v pbpaste >/dev/null; th
311
312
 
312
313
  This contract is validated by:
313
314
 
314
- - `smoke-cross-cli-behavior.sh` - asserts all 35 commands behave identically, pulls from Section 2 (placeholder vocab), Section 5 (argument parsing), Section 6 (output formats); also regression-locks the 6-persona agent deployment
315
+ - `smoke-cross-cli-behavior.sh` - asserts all 37 commands behave identically, pulls from Section 2 (placeholder vocab), Section 5 (argument parsing), Section 6 (output formats); also regression-locks the 6-persona agent deployment
315
316
  - `smoke-commands-skills-parity.sh` (50 assertions) - enforces colon-form command ↔ dash-form skill directory parity
316
317
  - `smoke-compliance-skills.sh` (45 assertions) - enforces store-compliance skill catalog + 4 consumer wiring
317
318
  - `smoke-personal-data.sh` - extended in 0.5.5 to treat deprecated placeholders (`{github-username}`, `{your-website}`, `{website-repo}`) as leaks; adds `mmerterden` to public-handle blocklist for generic docs
@@ -0,0 +1,197 @@
1
+ # Generate Issue - Shared Flow (generate-task / generate-bug)
2
+
3
+ > **TLDR** - Shared 11-step flow for `/multi-agent:generate-task` and `/multi-agent:generate-bug`. Mines the target project's existing issues to learn team conventions, detects the active sprint, drafts a standards-compliant issue, asks the user about every genuinely unknown field, renders a full preview, and creates the Jira issue only after explicit approval. Creates exactly one Jira issue per run - no branches, no commits, no worktrees.
4
+
5
+ Consumed by `generate-task.md` and `generate-bug.md` via their profile blocks (`ISSUE_TYPE`, default description sections, JQL sample filter). This ref is never invoked directly.
6
+
7
+ ## Hard rules (must not regress)
8
+
9
+ - **Approval gate is absolute.** Step [8/11] (full preview + explicit approval) runs on every invocation. There is no autopilot variant of these commands and no preference that skips the gate. `Cancel` means nothing was created.
10
+ - **Never invent content.** Anything the user did not supply and mining could not derive stays an open question (step [7/11]) or an explicitly empty section - never fabricated repro steps, environments, or acceptance criteria.
11
+ - **Issue content language follows `prefs.global.outputLanguage`.** Summary and description are written in the user's output language (intentional exception to the "external payloads stay English" default - the issue is authored FOR the user's team). Code identifiers, file paths, and URLs stay verbatim. AskUserQuestion `question`/`description` also follow `outputLanguage`; `label`/`header` stay English.
12
+ - **UTF-8 verbatim POST path** (same as `refs/channels/jira.md`): description body goes to a file, `jq -n --rawfile` builds the payload, `curl --data-binary @file` ships it. Never round-trip through `unicode_escape`/`latin-1`, never hand-roll a re-encoding helper. Jira wiki markup (`h3.` headings, `[text|url]` links), real newlines, no HTML entities.
13
+ - **Humanizer pass** on the description body after composition, before the preview render.
14
+ - **Read-only until approval.** Steps 1-8 perform only GET requests. The first write of any kind is the `POST /rest/api/2/issue` in step [9/11].
15
+
16
+ ## Flow
17
+
18
+ ### [1/11] Pick account (`_account-picker`)
19
+
20
+ ```bash
21
+ ACCOUNTS=$(~/.claude/lib/account-resolver.sh --providers jira)
22
+ TOKEN=$(~/.claude/lib/credential-store.sh get "$ACCOUNT_JIRA_TOKEN_KEY")
23
+ ```
24
+ - Single account → auto-select silently (picker-contract behavior); multiple → AskUserQuestion.
25
+ - Output: `ACCOUNT_JIRA_TOKEN_KEY`, `ACCOUNT_JIRA_HOST`.
26
+ - Token missing/expired → Token Save Flow from `setup.md` inline; user skips → abort, nothing created.
27
+
28
+ ### [2/11] Resolve project key
29
+
30
+ Fallback chain (same as `refs/issue-jira-triad.md` Create path):
31
+ 1. `figmaConfig.jira.projectKey` (per-project config, when running inside a configured repo)
32
+ 2. `prefs.global.defaultJiraKey`
33
+ 3. Fetch and ask:
34
+ ```bash
35
+ curl -s -H "Authorization: Bearer $TOKEN" \
36
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/project" \
37
+ | python3 -c 'import json,sys; [print(p["key"]+"\t"+p["name"]) for p in json.load(sys.stdin)]'
38
+ ```
39
+ AskUserQuestion (single-select) → cache the choice to `prefs.global.defaultJiraKey`.
40
+ - Output: `PROJECT_KEY`.
41
+
42
+ ### [3/11] Parse input
43
+
44
+ - Any `figma.com` URL in `$ARGUMENTS` → `FIGMA_URL`. Node-id normalization: `-` → `:`. Branch URLs use `branchKey` as effective `fileKey` (see `rules/figma-pipeline.md` URL parsing).
45
+ - Everything else → `FREE_TEXT`.
46
+ - Both empty → AskUserQuestion (free-text, in `outputLanguage`): "Describe the {task|bug} you want to open."
47
+ - `FIGMA_URL` is always optional. Never ask for one; only use it when given.
48
+
49
+ ### [4/11] Convention mining + field discovery + sprint detection (read-only)
50
+
51
+ Three GET groups. Run them before drafting anything.
52
+
53
+ **4a. Sample recent same-type issues:**
54
+ ```bash
55
+ JQL="project = ${PROJECT_KEY} AND issuetype = ${ISSUE_TYPE} ORDER BY created DESC"
56
+ curl -s -H "Authorization: Bearer $TOKEN" \
57
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/search?jql=$(printf '%s' "$JQL" | python3 -c 'import sys,urllib.parse; print(urllib.parse.quote(sys.stdin.read()))')&fields=summary,description,labels,components,priority,fixVersions&maxResults=30"
58
+ ```
59
+ Extract from the sample (thresholds are guidance, not hard gates):
60
+ - **Summary prefix pattern**: leading `[...]` or `AREA:` token frequency. Appears in >= 40% of samples → adopt as suggested prefix; top 2-3 prefixes become AskUserQuestion options in step 7 when ambiguous.
61
+ - **Description heading set**: lines matching `h[1-4]\.` or `*bold*` header style, frequency-ranked. A heading set shared by >= 50% of samples overrides the profile's default sections - the team template wins.
62
+ - **Top labels / components**: top 5 each by frequency → option lists for step 7.
63
+ - **Priority norm**: modal priority for this issuetype → pre-filled default, editable in preview.
64
+ - **Epic usage rate**: share of sampled issues carrying an epic link → decides whether step 7 asks for an epic.
65
+
66
+ **4b. Field discovery (createmeta):**
67
+ ```bash
68
+ curl -s -H "Authorization: Bearer $TOKEN" \
69
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/issue/createmeta?projectKeys=${PROJECT_KEY}&issuetypeNames=${ISSUE_TYPE}&expand=projects.issuetypes.fields"
70
+ ```
71
+ - 404 or empty `projects[]` (newer Jira DC deprecates the classic form) → fall back to the paged endpoint: `GET /rest/api/2/issue/createmeta/{PROJECT_KEY}/issuetypes` then `GET /rest/api/2/issue/createmeta/{PROJECT_KEY}/issuetypes/{issuetypeId}`.
72
+ - Every field with `required: true` beyond project/issuetype/summary/description/reporter → step 7 question (options from `allowedValues` when present, free-text fallback).
73
+ - Generic custom-field detection by `schema.custom` id - never assume field ids:
74
+ - Sprint: `com.pyxis.greenhopper.jira:gh-sprint`
75
+ - Epic Link: `com.pyxis.greenhopper.jira:gh-epic-link`
76
+ - Team-like fields: case-insensitive name match on `Team`
77
+ - 403 → warn "cannot read project field metadata", continue with profile defaults; required fields surface reactively via the 400 path in step 9.
78
+
79
+ **4c. Board + active sprint (Agile REST):**
80
+ ```bash
81
+ curl -s -H "Authorization: Bearer $TOKEN" \
82
+ "https://$ACCOUNT_JIRA_HOST/rest/agile/1.0/board?projectKeyOrId=${PROJECT_KEY}"
83
+ curl -s -H "Authorization: Bearer $TOKEN" \
84
+ "https://$ACCOUNT_JIRA_HOST/rest/agile/1.0/board/${BOARD_ID}/sprint?state=active"
85
+ ```
86
+ - Multiple boards → AskUserQuestion (board name + type). One board → silent. Zero boards or Agile API 404 → the sprint option is silently omitted; the preview notes "backlog only (no board found)".
87
+ - Active sprint found → remember `SPRINT_ID` + name for the step 7 placement choice. None → backlog only; if a `state=future` sprint exists, mention it in the preview as information.
88
+
89
+ ### [5/11] Figma context (only when `FIGMA_URL` is set)
90
+
91
+ Follow the 3-tier chain from `rules/figma-pipeline.md`: Tier 1 MCP (`get_design_context` / `get_screenshot`, one re-auth retry) → Tier 2 REST (`keychainMapping.figma_pat`) → Tier 3 ask the user for a screenshot or proceed link-only.
92
+
93
+ > This command is standalone (same class as `/multi-agent:analysis`), so Figma MCP use here is allowed - it is not a dev-phase violation under the "No MCP outside analysis phase" rule.
94
+
95
+ - Output: frame name, node id, optional screenshot PNG in `/tmp/generate-issue-$$-figma.png` for the step 10 attachment opt-in.
96
+ - Any tier failure degrades gracefully; Figma never blocks issue creation. Link-only is always acceptable.
97
+
98
+ ### [6/11] Compose draft
99
+
100
+ Write summary + description in `outputLanguage`:
101
+ - **Summary**: `{minedPrefix} {concise title}`, truncated to 255 chars.
102
+ - **Description**: mined heading set from 4a (or the profile's default sections when mining found no dominant template), in Jira wiki markup (`h3.` headings).
103
+ - Task profile fills: Goal, Scope, Acceptance Criteria, Notes from `FREE_TEXT`.
104
+ - Bug profile fills: Steps to Reproduce, Expected Result, Actual Result, Environment, Notes from `FREE_TEXT`.
105
+ - Missing information stays an open question for step 7 - never invented.
106
+ - `FIGMA_URL` set → add `h3. Design Reference` with `[Figma|{FIGMA_URL}]` + frame name + node id.
107
+ - Run the humanizer skill on the description body.
108
+ - Write the final body to `/tmp/generate-issue-$$.txt` (UTF-8, real newlines) for the `--rawfile` POST.
109
+
110
+ ### [7/11] Clarifying questions (only genuinely unknown fields)
111
+
112
+ Batched AskUserQuestion(s), each with a "Skip / leave unset" option where Jira allows it:
113
+ - **Component**: mined top components + "none" - only when the project uses components.
114
+ - **Epic link**: only when 4a epic usage rate is high. Options from `project = {KEY} AND issuetype = Epic AND statusCategory != Done`.
115
+ - **Priority**: only when the mined norm is ambiguous; otherwise pre-fill the norm and let the preview edit change it.
116
+ - **Labels**: mined top labels, multiSelect.
117
+ - **Assignee**: "me / unassigned / someone else".
118
+ - **Sprint placement**: "Active sprint: {name}" vs "Backlog" - only when an active sprint exists.
119
+ - **Required custom fields** from 4b not yet resolved (allowedValues as options).
120
+ - **Bug profile**: Steps to Reproduce or Environment underivable from `FREE_TEXT` → ask here.
121
+
122
+ Rule: never ask about anything already answerable from mining or the input. Regardless of how complete the draft looks, step 8 always runs.
123
+
124
+ ### [8/11] Full preview + approval gate (never skipped)
125
+
126
+ Render the complete issue in chat: project, issuetype, summary, the full description body, priority, labels, components, epic, assignee, sprint/backlog placement, attachment plan (Figma screenshot upload - default off, opt-in).
127
+
128
+ Then AskUserQuestion (`question` in `outputLanguage`, e.g. tr: "Bu sekilde olusturuyorum, onayliyor musun?"):
129
+
130
+ | Option | Behavior |
131
+ |---|---|
132
+ | `Approve` | Proceed to step 9 |
133
+ | `Edit` | Free-text "what should change?" → apply → re-render the FULL preview → re-ask. Loop, no iteration cap |
134
+ | `Cancel` | Stop. Nothing was created; say so explicitly |
135
+
136
+ This gate has no bypass. No flag, mode, or preference suppresses it.
137
+
138
+ ### [9/11] Create
139
+
140
+ ```bash
141
+ jq -n --rawfile desc /tmp/generate-issue-$$.txt \
142
+ --arg key "$PROJECT_KEY" --arg type "$ISSUE_TYPE" --arg summary "$SUMMARY" \
143
+ '{fields: {project: {key: $key}, issuetype: {name: $type}, summary: $summary, description: $desc}}' \
144
+ > /tmp/generate-issue-$$-payload.json
145
+ # merge approved optional fields (priority / labels / components / epic / assignee / required customs) into .fields with jq before POST
146
+ curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
147
+ --data-binary @/tmp/generate-issue-$$-payload.json \
148
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/issue"
149
+ ```
150
+ - Parse `key` from the response → `NEW_KEY`.
151
+ - 400 with field errors → show Jira's per-field error verbatim, return to step 7 for exactly those fields, then re-run step 8 (full preview again).
152
+
153
+ ### [10/11] Post-create steps
154
+
155
+ Each step is failure-isolated: on error, warn + continue - the issue already exists.
156
+
157
+ 1. **Sprint** (when chosen in step 7/8):
158
+ ```bash
159
+ jq -n --arg key "$NEW_KEY" '{issues: [$key]}' > /tmp/generate-issue-$$-sprint.json
160
+ curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
161
+ --data-binary @/tmp/generate-issue-$$-sprint.json \
162
+ "https://$ACCOUNT_JIRA_HOST/rest/agile/1.0/sprint/${SPRINT_ID}/issue"
163
+ ```
164
+ Post-create move instead of a Sprint custom field in the create payload: field-id-agnostic, works on every Jira Software instance.
165
+ 2. **Figma remote link** (when `FIGMA_URL` set):
166
+ ```bash
167
+ curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
168
+ -d '{"object":{"url":"'"$FIGMA_URL"'","title":"Figma design"}}' \
169
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/issue/${NEW_KEY}/remotelink"
170
+ ```
171
+ 3. **Screenshot attachment** (only when opted in during preview):
172
+ ```bash
173
+ curl -sS -X POST -H "Authorization: Bearer $TOKEN" -H "X-Atlassian-Token: no-check" \
174
+ -F "file=@/tmp/generate-issue-$$-figma.png" \
175
+ "https://$ACCOUNT_JIRA_HOST/rest/api/2/issue/${NEW_KEY}/attachments"
176
+ ```
177
+
178
+ ### [11/11] Report
179
+
180
+ ```
181
+ Created {NEW_KEY}: https://{ACCOUNT_JIRA_HOST}/browse/{NEW_KEY}
182
+ ```
183
+ Plus one line per post-create step that ran (sprint placement, remote link, attachment) and any that were skipped with reason.
184
+
185
+ ## Error paths
186
+
187
+ | Condition | Behavior |
188
+ |---|---|
189
+ | Token missing/expired (401) | Token Save Flow from `setup.md` inline; user skips → abort with message, nothing created |
190
+ | Search 403 / createmeta denied | Warn "cannot read project conventions/fields"; continue with profile-default template; required fields asked reactively on 400 |
191
+ | Zero sampled issues (new project) | Skip mining, use profile defaults, note in preview "no prior issues to learn from" |
192
+ | Agile API 404 / no boards | Omit sprint choice, backlog implied, say so in preview |
193
+ | No active sprint | Offer backlog only; mention the next `state=future` sprint when one exists |
194
+ | Figma Tier 1 fails | Tier 2; Tier 2 fails → Tier 3 (ask screenshot or link-only). Never block issue creation on Figma |
195
+ | Create 400 (field errors) | Show per-field errors, loop back to step 7 for those fields, re-preview |
196
+ | Create 5xx / network | Show the error, offer one retry, then abort - keep `/tmp/generate-issue-$$.txt` and print its path so the draft survives |
197
+ | Post-create step failure | Warn + continue (issue exists); print a manual-fix hint |
@@ -21,6 +21,18 @@ When a token resolves but the service rejects it (401 / 403), do not silently sk
21
21
 
22
22
  The question asks a *choice*; the replacement value still flows through the clipboard, never chat. `smoke-no-token-prompt.sh` greps for value-prompts (`enter token`, `paste token`, `API key:`) - decision labels like `Regenerate` / `Skip and continue` do not trip it.
23
23
 
24
+ Expiry is also checked **proactively at init**: Phase 0 Step 0.7 (`refs/phases/phase-0-init.md`) probes every token the run will need with one cheap call each (cached via `global.serviceStatus`, TTL 300s) and runs this same decision at init instead of waiting for the first mid-run 401. The mid-run 401 path stays as the safety net.
25
+
26
+ #### Figma MCP token lifecycle (critical)
27
+
28
+ `figma_mcp` is the only OAuth token in the registry (`figu_` prefix, ~90-day expiry); everything else is a long-lived PAT. A dead MCP token silently degrades every Figma consumer to Tier 2/3, so its expiry is handled specially:
29
+
30
+ 1. **Refresh token**: the generation flow stores a refresh token under `<keychainMapping.figma_mcp>_Refresh`. `~/.claude/lib/figma-mcp-refresh.sh` performs a silent renewal (OAuth refresh grant; client credentials read from the `.figma-oauth.json` next to `prefs.global.tokenScripts.figma_mcp`). Exit 0 = renewed in place, no user interaction. This ALWAYS runs before any question is asked.
31
+ 2. **Generation script**: `prefs.global.tokenScripts.figma_mcp` may point to a user-owned script that produces a fresh MCP token via Dynamic Client Registration + browser OAuth and saves it to the Keychain. When silent renewal fails, the expired-token question offers **Regenerate now (script)** which runs it (interactive runs only - it opens a browser).
32
+ 3. **Fallbacks**: Token Save Flow (clipboard) or continue degraded on Tier 2 (REST PAT), per the Phase 0 Step 0.7 decision table.
33
+
34
+ `prefs.global.tokenScripts` maps service ids to user-owned generation scripts (`{"figma_mcp": "/path/to/start_mcp.sh"}`); paths are personal and live only in the local preferences file - never in synced command files. Script output is status lines only - token values never enter chat or logs.
35
+
24
36
  Reasons:
25
37
  - Asking for a token in chat leaks it into the conversation transcript and any audit log.
26
38
  - The user has already configured the keychain; missing/expired is a setup issue, not a per-run issue.
@@ -98,6 +98,44 @@ Log the resolved tier in the agent log:
98
98
 
99
99
  Full chain definition, REST endpoints, URL parsing, canonical-component contract: `pipeline/rules/figma-pipeline.md` "MUST: Figma access - 3-tier fallback chain (BLOCKING, pipeline-wide)". Do not duplicate it here.
100
100
 
101
+ #### Step 0.6 - Update check (advisory, opt-out via `prefs.global.updateCheck.enabled`)
102
+
103
+ Run `bash pipeline/scripts/update-check.sh` (cached per `updateCheck.ttlHours`, default 24h; 3s-bounded; every failure path silent). Empty output → continue. Output `<local>|<latest>` means a newer version exists:
104
+
105
+ - **Interactive**: log `→ update available: v<local> -> v<latest>`, ask ONE AskUserQuestion - **Update now** (recommended) / **Continue without updating**. On *Update now* (or `updateCheck.autoUpdate: true`, which skips the question): run the `/multi-agent:update` flow, log `→ updated to v<latest>`, continue the run (note in the log: already-loaded phase docs finish this run on the old version; full effect next session). On *Continue*: no re-ask until the TTL expires.
106
+ - **Autopilot**: never ask (zero-interaction contract). Log `→ update available: ... (log-only; run /multi-agent:update)` and continue - unless `autoUpdate: true`, then update silently first.
107
+
108
+ Advisory - NEVER blocks. Must run BEFORE Step 6 (worktree creation) so an accepted update cannot mutate `~/.claude` under a mid-phase run.
109
+
110
+ #### Step 0.7 - Token expiry pre-flight (runs before Step 1 fetch)
111
+
112
+ Validate the tokens THIS run will need before any of them is used mid-phase. Scope is derived, not exhaustive:
113
+
114
+ | Run signal | Tokens to probe | Cheap probe (1 call each) |
115
+ |---|---|---|
116
+ | Input is Jira-id / Jira-url | `jira` | `GET /rest/api/2/myself` |
117
+ | Input is GitHub issue / repo#N | `github` | `gh auth status` (or `GET /user`) |
118
+ | Remote is Bitbucket | `bitbucket_token` | `GET /rest/api/1.0/application-properties` |
119
+ | `reportChannels.confluence` true | `confluence` | `GET /rest/api/user/current` |
120
+ | Task carries a Figma reference | `figma_mcp` (Tier 1), `figma` (Tier 2) | MCP `initialize` POST to `mcp.figma.com/mcp`; `GET api.figma.com/v1/me` |
121
+
122
+ Results are cached in `global.serviceStatus` (existing TTL contract, default 300s) - a probe that ran in the last 5 minutes is not repeated.
123
+
124
+ **Valid** → continue silently (one log line: `→ token pre-flight: N ok`).
125
+
126
+ **Figma MCP expired / rejected - CRITICAL path.** The `figma_mcp` OAuth token (`figu_`) expires on a schedule (90 days), unlike the PATs. Because a dead MCP token silently degrades every Figma consumer to Tier 2/3 and has cost rebuild rounds, an expired `figma_mcp` is never deferred to mid-run:
127
+
128
+ 1. **Silent renewal first**: run `~/.claude/lib/figma-mcp-refresh.sh` (refresh grant via `<key>_Refresh` + the `.figma-oauth.json` client credentials next to `prefs.global.tokenScripts.figma_mcp`). Exit 0 → re-probe, log `→ figma mcp token renewed silently`, continue. No question asked.
129
+ 2. **Renewal impossible/rejected** (exit 1/2) → AskUserQuestion at init (`question`/`description` in `outputLanguage`): "Figma MCP token expired - update it now?"
130
+ - **Regenerate now (script)** - shown only when `prefs.global.tokenScripts.figma_mcp` is set: run that script (browser OAuth flow), then re-probe and continue.
131
+ - **Save a new token** - Token Save Flow from `setup.md` (clipboard path).
132
+ - **Continue degraded** - proceed on Tier 2 (REST PAT) for this run; log the downgrade.
133
+ 3. **Autopilot**: silent renewal only; if it fails, log `→ figma mcp token expired (autopilot: continuing on tier 2)` and continue degraded - never prompt.
134
+
135
+ **Other tokens expired / rejected** → run the Expired-token decision from `refs/keychain.md` Rule 1 HERE at init (Regenerate / Use a different token / Skip and continue) instead of waiting for the first mid-run 401. A token that is structurally required for the input (e.g. the Jira PAT for a Jira-ID input) halts on skip, since Step 1 cannot fetch without it. Autopilot: skip-and-degrade semantics per Rule 1, halt only on structurally required tokens.
136
+
137
+ Probe failures caused by network (timeout, DNS) are NOT treated as expiry - log and continue; the mid-run 401 path still exists as the safety net.
138
+
101
139
  #### Step 1 - Parse Input
102
140
 
103
141
  **Branch from input**: If the user provided a branch name after the issue reference (space-separated), store as `baseBranch` and skip Step 3. Otherwise Step 3 asks interactively.
@@ -517,8 +555,8 @@ Log: `Phase 0 Step 7: taskType = {component|bugfix|feature|refactor|chore}`
517
555
  After each clarifier call:
518
556
 
519
557
  ```bash
520
- pipeline/scripts/log-metric.sh "$TASK_ID" 0 clarify.call \
521
- score=$SCORE questions=$Q stop_and_ask=$STOP autopilot_mode=$AP \
558
+ LOG_METRIC_FORWARD_TO_TRACKER=1 pipeline/scripts/log-metric.sh "$TASK_ID" 0 clarify.call \
559
+ model=haiku score=$SCORE questions=$Q stop_and_ask=$STOP autopilot_mode=$AP \
522
560
  duration_ms=$D tokens_in=$TI tokens_out=$TO
523
561
  ```
524
562
 
@@ -49,6 +49,16 @@ When Phase 0 Step 7 classified the task as `component`, Phase 3 delegates the en
49
49
 
50
50
  For non-component taskTypes (`bugfix`, `feature`, `refactor`, `chore`), continue with the standard TDD section below.
51
51
 
52
+ #### Design fidelity contract (BLOCKING when the task carries a Figma reference)
53
+
54
+ Applies to EVERY task whose analysis doc carries design ground truth (Section 6 rows, node IDs, screenshots) - component-dispatch AND TDD-path UI work alike. MCP stays forbidden here (analysis-only rule); the analysis doc IS the design:
55
+
56
+ 1. **1:1, not interpretation.** The captured frames are the reference for every UI line. Layout, variant states, copy, and colours come from the analysis doc's measured values - never eyeballed, never "close enough".
57
+ 2. **Code Connect decides the component.** A mapped component (`CodeConnectSnippet` / repo `*.figma.swift` / `*.figma.kt` row) MUST be used verbatim - sound-alike substitutes are forbidden; a missing modifier is added to the component's `+Modifiers` extension, never forked. No mapping exists -> write a NEW component per the Configuration/View/Modifiers architecture; never inline ad-hoc UI into the consumer screen.
58
+ 3. **Inter-component spacing is part of the design.** Gaps, paddings, and alignment BETWEEN components must match the frame's measured values, mapped to spacing tokens (`Spacing*`) - never invented numbers. A spacing/layout deviation is a `review_blocking` finding in Phase 4 Step 1.8, not a nitpick.
59
+
60
+ Missing design data (variant, padding, copy) → HALT and instruct the user to re-run `/multi-agent:analysis`; never guess and never call Figma MCP from this phase.
61
+
52
62
  #### Re-entry from Phase 4 triage
53
63
 
54
64
  Phase 3 runs twice in the pipeline lifetime: first for initial development, then optionally for rework after Phase 4 review. **Phase 3 never acts on raw reviewer output.** It only consumes `triage.accepted` findings - Fable triage in Phase 4 already filtered false-positives, deferred out-of-scope items, and rejected noise.
@@ -286,6 +296,8 @@ When `agent-state.json.onlyDevelop === true`, Phase 3 runs self-contained with *
286
296
 
287
297
  **Combinable with autopilot**: `--dev autopilot` = zero interaction. Init → Dev → auto-commit → auto-PR → Report.
288
298
 
299
+ **Tracker visibility during Opus dispatch**: on Claude Code the model switch to Opus happens via subagent dispatch, and the parent widget cannot move while an Agent call is in flight. Dispatch per task from the self-generated task list (never one monolithic call for the whole phase), set the pre-dispatch `activeForm` marker, and record tokens between chunks - full rules in `refs/tracker-contract.md` section "Delegated phases".
300
+
289
301
  ---
290
302
 
291
303
  #### v2.1.0+ Multi-Repo Mode
@@ -157,6 +157,8 @@ When `state.evidence.figma[]` is non-empty, the reviewer subagents MUST receive
157
157
 
158
158
  Visual-fidelity mismatches against the captured screenshot are BLOCKING findings, not nits:
159
159
 
160
+ - Canonical component usage: the Code Connect-mapped component is used verbatim - a sound-alike substitute, a forked copy, or ad-hoc inline UI where a mapping exists is blocking (Phase 3 "Design fidelity contract")
161
+ - Inter-component spacing: gaps, paddings, and alignment BETWEEN components match the design's measured values mapped to spacing tokens - invented numeric values are blocking
160
162
  - Avatar icon (presence, glyph, shape, position)
161
163
  - Field grouping (one rounded box vs two; separator vs gap)
162
164
  - Character counter visibility
@@ -390,30 +392,9 @@ After the triage verdict is computed, populate `triage.consensus`:
390
392
 
391
393
  ##### 3.7 Verify-by-test (opt-in, empirical validation of blocking findings)
392
394
 
393
- **Rationale:** a triage verdict is still a judgment call; a failing repro test is proof. Debating a finding costs tokens, running it costs one test invocation and kills false positives that survive adversarial framing.
395
+ A triage verdict is judgment; a failing repro test is proof. Runs only when `prefs.global.verifyByTest.enabled` is `true` AND `accepted` contains a `blocking` finding; otherwise skip silently. **Full contract (verdict table, cleanup invariant, prompts): `refs/features/verify-by-test.md` - read it before executing this step.**
394
396
 
395
- **Gate:** runs only when `prefs.global.verifyByTest.enabled` is `true` AND the validated triage output contains at least one `accepted` finding with `severity: "blocking"`. Otherwise skip silently (no log noise). Full behavior spec: `refs/features/verify-by-test.md`.
396
-
397
- 1. **Dispatch ONE verifier agent** (subagent_type: `general-purpose`, model: `prefs.global.verifyByTest.model`, default `sonnet`) for the iteration - not one per finding. Input: up to `verifyByTest.maxFindings` (default 3) accepted blocking findings (ordered as triage returned them), the diff hunks for their files, and the project's test conventions from Phase 1. Findings beyond the cap keep their judgment-only verdict; log `verify_by_test=cap-exceeded count=<n>`.
398
- 2. **Per finding, the verifier writes ONE minimal repro test** asserting the CORRECT behavior the finding claims is broken, following the platform test conventions (framework, naming, location per phase-3-dev.md), then runs ONLY that test using the platform single-test invocation from Phase 3 (`xcodebuild test -only-testing:`, `pytest {file}::{name}`, `npm test -- --testPathPattern=`, `./gradlew test --tests`), wrapped in `acquire_build_lock`/`release_build_lock`, log tee'd to `$WORKTREE/.pipeline/verify-<i>.test.log`.
399
- 3. **Verdict mapping (fails toward keeping blockers):**
400
-
401
- | Repro test outcome | `verification.result` | Action on finding |
402
- | --- | --- | --- |
403
- | Test FAILS as the finding predicts | `confirmed` | Stays `accepted` blocking. Repro test is KEPT in the worktree and recorded in `redTests[]` as the RED test for the Phase 3 rework loop. |
404
- | Test PASSES (defect not reproducible) | `not-reproduced` | Downgrade is evidence-gated: `node pipeline/scripts/evidence-gate.mjs --claim test --status passed --evidence "$WORKTREE/.pipeline/verify-<i>.test.log"` must exit 0. On exit 0: move finding from `accepted[]` to `deferred[]` with reason `verify-by-test: not reproduced - repro test <testRef> passed`, delete the repro test file. On exit non-zero: treat as `inconclusive`. |
405
- | Compile error, timeout, or defect not expressible as a unit test | `inconclusive` | Stays `accepted` blocking (judgment-only verdict stands). Partial test file deleted, cause noted in `verification.note`. |
406
-
407
- 4. **Cleanup invariant:** after Step 3.7 the only verifier artifacts left in the worktree are the confirmed repro tests listed in `redTests[]` (they get committed with the fix, satisfying the TDD contract) and logs under `$WORKTREE/.pipeline/` (already outside Phase 6 commit scope).
408
- 5. **Persist + re-validate:** stamp each verified finding with a `verification` object (schema v3.2.0), persist `state.reviewIterations[-1].verifyByTest = { attempted, confirmed, downgraded, inconclusive, redTests: [{file, testRef, issue}] }`, recompute `approved`, then re-run `validate-triage.mjs` on the mutated `$TRIAGE_FILE` under the same 3.2.1 gate protocol.
409
- 6. **Timeout/fallback (mirrors 3.3):** the whole step is bounded by `verifyByTest.stepTimeoutSec` (default 600). On verifier crash or budget breach: no retry; remaining findings keep judgment-only verdicts, log `triage=verify-by-test-timeout`, proceed to Step 4. Never blocks the pipeline.
410
-
411
- Telemetry (per 3.4 conventions, best-effort):
412
-
413
- ```bash
414
- LOG_METRIC_FORWARD_TO_TRACKER=1 pipeline/scripts/log-metric.sh "$TASK_ID" 4 review.verify_by_test \
415
- attempted=$A confirmed=$C downgraded=$D inconclusive=$I duration_ms=$MS
416
- ```
397
+ Compressed flow: dispatch ONE verifier agent (model `verifyByTest.model`, default `sonnet`) for up to `maxFindings` (default 3) accepted blocking findings. Per finding it writes ONE minimal repro test and runs ONLY that test (Phase 3 single-test invocation, build lock, log tee'd to `$WORKTREE/.pipeline/verify-<i>.test.log`). Outcomes: test FAILS as predicted -> `confirmed`, finding stays blocking and the test is KEPT in `redTests[]` as the Phase 3 rework RED test; test PASSES -> `not-reproduced` ONLY if `evidence-gate.mjs --claim test --status passed` exits 0 on the log, finding moves to `deferred[]`, test deleted; compile error / timeout / not unit-testable -> `inconclusive`, judgment verdict stands. Stamp findings with `verification` (schema v3.2.0), persist `state.reviewIterations[-1].verifyByTest = {attempted, confirmed, downgraded, inconclusive, redTests[]}`, recompute `approved`, re-run `validate-triage.mjs` under the 3.2.1 gate. Whole step bounded by `stepTimeoutSec` (default 600); on breach or crash remaining findings keep judgment verdicts - never blocks. Telemetry per 3.4: `review.verify_by_test attempted= confirmed= downgraded= inconclusive= duration_ms=`.
417
398
 
418
399
  #### Step 4 - Consensus + Action (triage-driven)
419
400
 
@@ -95,7 +95,12 @@ Tier 1 / Tier 2 records print `screenshotUrl` from the captured evidence (Tier 2
95
95
  "ok" -> proceeds to Phase 6 (WIP commit will be replaced via git reset HEAD~1 + proper commit)
96
96
  "fix: ..." -> worktree is recreated, returns to Phase 3
97
97
  ```
98
- 5. Wait for user response
98
+ 5. Mark the tracker as waiting, then wait for the user response:
99
+ ```bash
100
+ bash $HOME/.claude/scripts/phase-tracker.sh now 5 "awaiting local test (user)"
101
+ bash $HOME/.claude/scripts/phase-tracker.sh render
102
+ ```
103
+ The waiting state persists in `tracker-state.json` across the handoff; `/multi-agent:finish` and `/multi-agent:manual-test` CONTINUE this state file and never re-init it (`refs/tracker-contract.md` "Continuation runs").
99
104
  6. If fix needed:
100
105
  - Branch already has WIP commit (from step 2) - changes are safe
101
106
  - Recreate worktree from branch: `git -C $PROJECT_ROOT worktree add {worktree-path} {branch}`
@@ -101,6 +101,8 @@ Tracker: `phase-tracker.sh sub 7 1 "Channels dispatch" completed` (or `failed` i
101
101
 
102
102
  Runs only when `state.tracker.kind === "github-issue"`. The Issue adapter is mandatory whenever the run was triggered from a GitHub issue - no exceptions, no "I'll just update the flags" shortcut. Full template + rules: `refs/channels/issue-comment.md`.
103
103
 
104
+ **Approval gate:** interactive runs show the composed comment body (and the Progress-flag diff intent) through the same preview + approval gate as channels Step 6 (`channels.md`) before posting - Approve & post / Edit / Cancel. Autopilot posts directly.
105
+
104
106
  Two paired actions, in order:
105
107
 
106
108
  ```bash
@@ -182,9 +184,11 @@ Skipped sections: when `planTodos.enabled` is false or no `plan.todos[]` was emi
182
184
  (embed `aggregate-metrics.mjs --since=<30 days ago> --json` output as collapsed JSON)
183
185
  ```
184
186
 
185
- **Telemetry emission** (mandatory): emit final event:
187
+ **Telemetry emission** (mandatory): forward the phase's own LLM spend (humanizer + report compose calls) to the tracker, then emit the final event:
186
188
 
187
189
  ```bash
190
+ LOG_METRIC_FORWARD_TO_TRACKER=1 pipeline/scripts/log-metric.sh "$TASK_ID" 7 report.compose \
191
+ model=$REPORT_MODEL tokens_in=$R_IN tokens_out=$R_OUT duration_ms=$R_DUR
188
192
  pipeline/scripts/log-metric.sh "$TASK_ID" 7 task.completed \
189
193
  phases=$PHASE_COUNT review_cycles=$CYCLES lang=$PROMPT_LANG \
190
194
  channels_pr=$PR_STATUS channels_jira=$JIRA_STATUS \
@@ -21,6 +21,7 @@ Today pipeline users see a phase banner (`→ Phase 3: Dev`) and then silence fo
21
21
  - **verb** - lowercase present participle or imperative, one word: `fetching`, `reading`, `running`, `writing`, `posting`, `waiting`, `dispatching`, `retrying`, `building`, `committing`, `checking`.
22
22
  - **object** - what is being acted on: file basename, API endpoint last segment, subagent name, command, smoke name.
23
23
  - **target** - optional, human-readable scope: repo name, ticket ID, URL host.
24
+ - **Live mirror to the phase tracker**: each `normal`-tier emitted line is also mirrored to the active phase per `refs/tracker-contract.md` "Active phase" (Claude Code `TaskUpdate activeForm`, other CLIs `phase-tracker.sh now`) - the authoritative throttling rules live there.
24
25
 
25
26
  ### Examples
26
27