@mmerterden/multi-agent-pipeline 14.1.1 → 14.2.1

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 (34) hide show
  1. package/CHANGELOG.md +120 -0
  2. package/package.json +1 -1
  3. package/pipeline/commands/deploy.md +4 -1
  4. package/pipeline/commands/multi-agent/SKILL.md +6 -3
  5. package/pipeline/commands/multi-agent/help/SKILL.md +49 -11
  6. package/pipeline/commands/multi-agent/setup/SKILL.md +1 -1
  7. package/pipeline/commands/multi-agent/store-ready/SKILL.md +340 -0
  8. package/pipeline/commands/multi-agent/sync/SKILL.md +4 -3
  9. package/pipeline/commands/multi-agent/test/SKILL.md +18 -8
  10. package/pipeline/commands/multi-agent/test-accessibility/SKILL.md +33 -0
  11. package/pipeline/commands/multi-agent/test-dark-mode/SKILL.md +33 -0
  12. package/pipeline/commands/multi-agent/test-dynamic-type/SKILL.md +33 -0
  13. package/pipeline/commands/multi-agent/test-screenshots/SKILL.md +41 -0
  14. package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +28 -201
  15. package/pipeline/commands/sim-test.md +45 -36
  16. package/pipeline/multi-agent-refs/cross-cli-contract.md +3 -2
  17. package/pipeline/multi-agent-refs/knowledge.md +1 -1
  18. package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
  19. package/pipeline/schemas/prefs.schema.json +1 -1
  20. package/pipeline/skills/.skills-index.json +48 -3
  21. package/pipeline/skills/shared/README.md +11 -6
  22. package/pipeline/skills/shared/core/multi-agent/SKILL.md +13 -17
  23. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +50 -12
  24. package/pipeline/skills/shared/core/multi-agent-purge/SKILL.md +18 -3
  25. package/pipeline/skills/shared/core/multi-agent-store-ready/SKILL.md +50 -0
  26. package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +4 -3
  27. package/pipeline/skills/shared/core/multi-agent-test/SKILL.md +18 -8
  28. package/pipeline/skills/shared/core/multi-agent-test-accessibility/SKILL.md +37 -0
  29. package/pipeline/skills/shared/core/multi-agent-test-dark-mode/SKILL.md +37 -0
  30. package/pipeline/skills/shared/core/multi-agent-test-dynamic-type/SKILL.md +37 -0
  31. package/pipeline/skills/shared/core/multi-agent-test-screenshots/SKILL.md +44 -0
  32. package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +29 -101
  33. package/pipeline/skills/shared/external/firebase/SKILL.md +1 -1
  34. package/pipeline/skills/skills-index.md +8 -3
package/CHANGELOG.md CHANGED
@@ -16,6 +16,126 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [14.2.1] - 2026-07-30
20
+
21
+ ### Changed
22
+
23
+ - **`testflight-validation` merged into a new `/multi-agent:store-ready`, and the
24
+ Android side brought to parity.** The iOS archive audit existed twice with
25
+ identical arguments - `ios_app_store_audit({archive_path, rules: "all"})` in the
26
+ command's Gate 1 and again inside `sim-test.md`'s `store-ready` scenario. Two
27
+ copies of one call is how the second door grew with no Gate 2, no Gate 3 and no
28
+ Android equivalent. There is now one implementation.
29
+ Gates are symmetric per platform, because the failure modes are: a malformed
30
+ package, a package the store itself refuses, and a policy a human enforces.
31
+
32
+ | Gate | iOS | Android |
33
+ |---|---|---|
34
+ | 1 Static | `ios_app_store_audit`, 18 rules | `android_apk_audit` + `google-play-compliance`, 21 rules |
35
+ | 2 Authoritative | `altool --validate-app` | `SKIPPED` |
36
+ | 3 Policy | `app-store-review` vs source | `play-store-review` vs source |
37
+
38
+ Gate 2's asymmetry is reported as an asymmetry rather than smoothed over: Play's
39
+ authoritative check exists only server-side, through a Publishing API draft edit,
40
+ and the pipeline ships no client for it. An Android run therefore clears at most
41
+ 2 of 3 and never prints `passed`. `bundletool validate` is Gate 1 and is not
42
+ promoted to fill the hole.
43
+ The running-app sweep became Step A rather than a separate errand - a build can
44
+ be structurally perfect and still ship an unreadable screen - and it degrades to
45
+ `SKIPPED (no booted device)` instead of halting the package validation.
46
+
47
+ Nothing was removed. `testflight-validation` is a thin iOS-pinned alias (removing
48
+ a command is a breaking change to the slash-command surface), and
49
+ `test "store-ready"` still resolves, now as a hand-off. `sim-test.md` keeps only
50
+ the pointer, so a dark-mode run no longer loads altool and credential-tier prose
51
+ it never needs.
52
+
53
+ ### Added
54
+
55
+ - **Four fixed-scenario `test-*` commands.** `/multi-agent:test-dark-mode`,
56
+ `:test-accessibility`, `:test-dynamic-type` and `:test-screenshots [locale]` pin a
57
+ scenario the quoted-tag form made you remember and quote. Typing `test-` now
58
+ autocompletes the matrix list instead of returning a single entry whose tags live
59
+ only in the help text. The scenario-tag form is unchanged and not deprecated -
60
+ each command is an alias for it, delegating to the same `sim-test.md`, so there is
61
+ one implementation and no forked logic. Same pattern the mode aliases already use
62
+ (`:dev-autopilot` = `--dev autopilot`).
63
+ `screenshot <lang>` became `test-screenshots [locale]` rather than
64
+ `test-screenshot-tr`: the locale is a parameter, and freezing one language into a
65
+ command name buys one command per language. `store-ready` deliberately got no
66
+ alias - it takes an optional archive path, and its 18-rule audit is the same one
67
+ `/multi-agent:testflight-validation` runs as its first gate, so the alias would
68
+ have advertised a second door onto a duplicate.
69
+
70
+ ### Fixed
71
+
72
+ - **Copilot's `purge` could not see a single worktree.** It discovered them with
73
+ `find {repo}/.worktrees/ -name "agent-state.json"`, and no worktree carries that
74
+ file: Phase 0 writes state to `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`.
75
+ Verified on a repo with two live task worktrees - the marker scan returns zero
76
+ while `purge.sh`'s own directory enumeration finds both. So the skill reported
77
+ "nothing to purge" as success with real worktrees on disk. The Claude Code command
78
+ had already been fixed by delegating to `purge.sh`; the Copilot mirror never
79
+ received that fix, which is the second time a repaired Claude-side surface left its
80
+ Copilot counterpart behind in this release.
81
+ It now delegates to the script and explicitly forbids re-introducing a
82
+ marker-file scan.
83
+ - **The stale log location survived in four more places** after `clear-logs` was
84
+ redirected. `shared/core/multi-agent` told Phase 0 to create `agent-log.md` and
85
+ `agent-state.json` inside `.worktrees/PROJ-{id}/`, told `:resume` to look for state
86
+ there, and printed that path as the report location; `phase-0-init` said "create log
87
+ dir" without naming one, 49 lines above the line that does. All four now name
88
+ `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`, the path the tracker,
89
+ `prune-logs.sh` and `:resume` actually read.
90
+ `status` and `log` keep their worktree scan as a legacy fallback: it finds nothing
91
+ on a current tree, but it is harmless and would still serve an old one.
92
+
93
+ - **`clear-logs` scanned a path nothing writes to, and help advertised it as a
94
+ slash command that does not exist.** It looked for
95
+ `.worktrees/PROJ-*/agent-log.md` and `agent-state.json`; Phase 0 has written both
96
+ to `$HOME/.claude/logs/multi-agent/{project}/{task-id}/` since the layout moved.
97
+ Against the current tree the scan matches zero files, so the op reported "logs
98
+ cleared, deleted 0" as success while every real log stayed on disk - worse than a
99
+ missing command, because it reads as done. There was also no `clear-logs` command
100
+ directory, so the `/multi-agent:clear-logs` entry in the Copilot help pointed at a
101
+ slash command that was never installed.
102
+ The name is kept as a redirect to `prune-logs` rather than deleted, so an existing
103
+ invocation lands somewhere correct. `prune-logs` and `garbage-collect` now appear
104
+ in the Copilot help, matching the Claude Code side. This is the `finish` → `ship`
105
+ class of drift the inventory gate's own comment describes, in the files that gate
106
+ does not parse.
107
+ - **`sim-test.md` advertised two scenarios it never implemented.** `"biometric"` and
108
+ `"performance"` sat in the activation block with no implementation section, so
109
+ reaching either fell through to the general sweep and was reported as the scenario
110
+ asked for. Neither can be built symmetrically today: biometric has `ios_biometric`
111
+ and no Android counterpart, launch timing has `android_launch_time` and no iOS
112
+ counterpart, and the file auto-detects platform - so each would work on one
113
+ platform and silently do nothing on the other. Both rows are withdrawn with the
114
+ reason recorded in place, rather than shipped as half-features or left advertised.
115
+ Advertised scenarios and implemented sections now match one to one.
116
+ - **`help` never documented two shipped commands.** `testflight-validation` and
117
+ `ios-coding-standard` existed in the tree, installed correctly, and appeared in no
118
+ block of `help/SKILL.md` in either language - `ios-coding-standard` was reachable
119
+ only because it also sat in `prefs.global.routines`, i.e. it read as a personal
120
+ routine rather than a first-party command. Both are now in the EN and TR Post-Hoc
121
+ sections. A command absent from help is a command nobody runs.
122
+ - **Rule count drifted between the two language blocks.** The TR block advertised a
123
+ 17-rule iOS store audit against the EN block's 18 and `ios_app_store_audit`'s
124
+ actual 18. The TR reader was being given a number no code produces.
125
+
126
+ ### Changed
127
+
128
+ - **`DESC_CEILING` 78000 -> 81000**, with the paired pin in
129
+ `test/context-budget-gate.test.mjs` moved in the same commit, as that test
130
+ requires. Not a bump to silence a red gate: at 78000 the surface had **16 bytes**
131
+ of headroom, so any new command failed regardless of how tersely it was described,
132
+ while the gate's own average check sat at 320 against its 420 ceiling - the signal
133
+ that the tree grew rather than that descriptions are padded. The alternative was
134
+ shaving routing text off eight unrelated `shared/external` skills to fund four
135
+ commands, which trades a real capability for a cosmetic number. Both the gate and
136
+ the test now carry the ceiling's history inline so the next raise has to argue for
137
+ itself. Cost is honest: ~470 always-on tokens per run.
138
+
19
139
  ## [14.1.1] - 2026-07-30
20
140
 
21
141
  Three defects that all shared one shape: a name written in one place and read in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "14.1.1",
3
+ "version": "14.2.1",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -43,7 +43,10 @@ Run through the iOS deployment checklist before App Store submission.
43
43
  ### 6. Archive & Upload
44
44
 
45
45
  - [ ] Archive with Release configuration
46
- - [ ] Run App Store compliance scan: `/archive-guard <archive>` (uses `ios_app_store_audit` MCP tool)
46
+ - [ ] Run pre-submission validation: `/multi-agent:store-ready --archive=<archive>` - three gates
47
+ (static audit, Apple's own `altool --validate-app`, guideline review vs source).
48
+ `/archive-guard <archive>` is the quick single-gate form when only the static
49
+ audit is wanted.
47
50
  - [ ] Upload via Xcode Organizer or `xcrun altool`
48
51
  - [ ] Verify in App Store Connect
49
52
 
@@ -72,7 +72,7 @@ Lib scripts (`~/.claude/lib/`):
72
72
  | `log [id]` | Show task log |
73
73
  | `resume [id]` | Resume paused task |
74
74
  | `kill [id]` | Delete worktree (logs preserved). Confirm first |
75
- | `clear-logs` | Clean global log directory. Keep counter |
75
+ | `clear-logs` | **Superseded - redirect, do not run.** Say so and route to `prune-logs`. It targeted `.worktrees/PROJ-*/agent-log.md`, a path nothing has written to since logs moved to `$HOME/.claude/logs/multi-agent/{project}/{task-id}/`; running it would report deleting nothing as success. |
76
76
  | `purge` | Worktree + logs + counter - full reset (double confirm) |
77
77
  | `review [#N\|repo#N\|PR-url\|branch]` | Parallel review of a PR or branch diff; with no input (interactive) lists open GitHub + Bitbucket PRs to multi-select. Posts per-finding inline comments + approve/needs-work on PRs. No worktree. |
78
78
  | `review-jira [KEY\|url]` | Grade a Jira issue's readiness for the pipeline (scope / AC / repro / design / API / stack), then post the gaps as a Jira comment. Read-only on code. |
@@ -82,6 +82,8 @@ Lib scripts (`~/.claude/lib/`):
82
82
  | `channels [PR-url\|#N\|Jira-url\|Jira-id] [--channels pr,jira,confluence,wiki] [--content normal,test,auto-diff,note] [--message "..."]` | Post task report to multi-select channels (PR description, Jira comment, Confluence page, Wiki pages) with multi-select content sources. Humanizer pass per-channel. Bitbucket PR updates use reviewer-preserving PUT. Phase 7 delegates to this command; also invocable post-hoc for fixes made outside the pipeline. No worktree. |
83
83
  | `create-jira ["desc"] [figma-url] [swagger-url]` | Create a standards-compliant Jira issue: asks the type (**Task** / **Bug** / **Story**), mines the project's recent same-type issues for conventions (summary format, labels, priority, test-scenario style), detects the active sprint, drafts from a standard template with auto-sizing sections (Design Reference / API Contract / Screenshots appear only when their source is given), asks about unknown fields, then full draft preview + explicit approval before create. No worktree, no commits. |
84
84
  | `test` or `test [args]` | UI Bug Hunter - screenshot + tap + analyze on booted simulator via MCP (read `$HOME/.claude/commands/sim-test.md`). `/multi-agent:test` also resolves here via the `commands/multi-agent/test/SKILL.md` delegate. |
85
+ | `test-dark-mode` · `test-accessibility` · `test-dynamic-type` · `test-screenshots [locale]` | Fixed-scenario aliases for the four parameterless / single-parameter `test` scenarios, so the tag autocompletes instead of having to be quoted. Each delegates to the same `sim-test.md` with its scenario pinned; behaviour is identical to the quoted form, which is not deprecated. |
86
+ | `store-ready [repo] [--archive=\|--ipa=\|--aab=\|--apk=] [--skip-sweep]` | Pre-submission store readiness for a built **package**, iOS and Android, local-only. Three symmetric gates per platform - static package audit, the store's own validator, policy review vs repo source - plus the running-app sweep as Step A. A skipped gate is never folded into the pass count, and an Android run clears at most 2 of 3 because Play's authoritative check is server-side only. Validates only, never uploads. `testflight-validation` is the iOS-pinned alias; `test "store-ready"` hands off here. |
85
87
  | `manual-test [#id]` | Phase 5 standalone Manual Test - checks out the task branch, prints Xcode / SourceTree hints, waits for user verdict (`ok` / `fix: ...`). |
86
88
  | `design-check [scope]` | Mock-mode vs Figma design audit (iOS / Android, local-only). Pick repo + module → mock-support feasibility gate (halts if unsupported) → **scenario inventory** (every launch arg / scenario case / scenario code / fixture / deep link becomes a countable target with file+line evidence) → scope resolve (empty = module, screen, `screen@variant`, target id, Figma URLs, `--resume`) → worktree Debug build + mock launch → drive EACH target by its own driver, capturing tap-reachable sub-states with it → per-variant pixel + px-spacing + typography + color compare → report (side-by-side + annotated overlay + stacked findings + fix prompt) exported to `~/DesignChecks/` as HTML + PDF (+ Confluence if enabled). **Coverage gate**: a target is audited or skipped with a concrete reason, else the run is reported INCOMPLETE with the missing ids. No commits, no CI. |
87
89
  | `stack [ios\|android\|backend\|mobile\|all]` | Swap skills for next conversation. No arg = show current stack. |
@@ -113,7 +115,7 @@ This command uses lazy loading for token efficiency. Read the relevant sub-file
113
115
  | `help` | `$HOME/.claude/commands/multi-agent/help/SKILL.md` |
114
116
  | `channels` | `$HOME/.claude/commands/multi-agent/channels/SKILL.md` |
115
117
  | `sync` | `$HOME/.claude/commands/multi-agent/sync/SKILL.md` |
116
- | `clear-logs` | Handled inline - scan + delete agent-log.md/agent-state.json files |
118
+ | `clear-logs` | Handled inline - redirect to `prune-logs`, see the routing note |
117
119
  | `review` | `$HOME/.claude/commands/multi-agent/review/SKILL.md` |
118
120
  | `review-jira` | `$HOME/.claude/commands/multi-agent/review-jira/SKILL.md` (loads `$HOME/.claude/multi-agent-refs/readiness-review.md`) |
119
121
  | `review-issue` | `$HOME/.claude/commands/multi-agent/review-issue/SKILL.md` (loads `$HOME/.claude/multi-agent-refs/readiness-review.md`) |
@@ -136,10 +138,11 @@ This command uses lazy loading for token efficiency. Read the relevant sub-file
136
138
  | Token lookup needed | `$HOME/.claude/multi-agent-refs/keychain.md` |
137
139
  | Audit tools (Phase 5/6) | `$HOME/.claude/multi-agent-refs/audit-guide.md` |
138
140
  | `test` | `$HOME/.claude/commands/sim-test.md` (colon-form `/multi-agent:test` uses the delegate at `commands/multi-agent/test/SKILL.md`) |
141
+ | `test-dark-mode` · `test-accessibility` · `test-dynamic-type` · `test-screenshots` | `$HOME/.claude/commands/sim-test.md`, scenario pinned by the command name (delegates at `commands/multi-agent/test-*/SKILL.md`) |
139
142
  | `manual-test` | `$HOME/.claude/commands/multi-agent/manual-test/SKILL.md` |
140
143
  | `design-check` | `$HOME/.claude/commands/multi-agent/design-check/SKILL.md` |
141
144
 
142
- **Modifier flags** (`--dev`, `--local`, `autopilot`) and **ops** (`status`, `log`, `resume`, `kill`, `clear-logs`, `purge`, `review`) are parsed inline by this file - no separate spec files, they compose with the pipeline or do one-shot work.
145
+ **Modifier flags** (`--dev`, `--local`, `autopilot`) and **ops** (`status`, `log`, `resume`, `kill`, `purge`, `review`) are parsed inline by this file - no separate spec files, they compose with the pipeline or do one-shot work.
143
146
 
144
147
  **How**: After routing, `Read` the relevant file and follow its instructions. Only load what the current action needs.
145
148
 
@@ -119,6 +119,14 @@ Post-Hoc & Side-Channel:
119
119
  /multi-agent:search Cross-task log search with smart ranking; --semantic queries triage corpus
120
120
  /multi-agent:scan Skill security scan against tiered pattern catalog
121
121
  /multi-agent:refactor Adapted best-practices + bug hunt + upstream-drift + dev-toolkit MCP research -> one plan, approval, dev + sync
122
+ /multi-agent:store-ready [repo] [--archive=|--ipa=|--aab=|--apk=] [--skip-sweep] Pre-submission store readiness,
123
+ iOS + Android, local-only. Three symmetric gates per platform: static package audit,
124
+ the store's own validator, policy review vs repo source. Plus the running-app sweep.
125
+ A skipped gate is never counted as a pass. Validates only, never uploads.
126
+ /multi-agent:testflight-validation [repo] [--ipa=|--archive=] iOS-pinned alias of :store-ready, kept because it is
127
+ the name you reach for when the target is TestFlight. Same three gates, one implementation.
128
+ /multi-agent:ios-coding-standard [module] Audit an iOS module against the 99-rule coding-standard registry -> remediation
129
+ plan + one-page onboarding summary -> hand off to dev / dev-local. Read-only, never edits source.
122
130
 
123
131
  Setup & Maintenance:
124
132
 
@@ -156,11 +164,22 @@ Interactive Launchers:
156
164
  UI Testing (standalone - not part of pipeline phases):
157
165
 
158
166
  /multi-agent:test Full simulator test (screenshot all screens)
159
- /multi-agent:test "dark mode" Dark mode bug test
160
- /multi-agent:test "accessibility" Accessibility audit (labels, tap targets, contrast)
161
- /multi-agent:test "dynamic type" Large text size test
162
- /multi-agent:test "screenshot tr" App Store screenshots in Turkish
163
- /multi-agent:test "store-ready" App Store guideline pre-flight check
167
+
168
+ Fixed-scenario commands - no quoting, and they autocomplete off `test-`:
169
+
170
+ /multi-agent:test-dark-mode Dark mode bug test
171
+ /multi-agent:test-accessibility Accessibility audit (labels, tap targets, contrast)
172
+ /multi-agent:test-dynamic-type Large text size test
173
+ /multi-agent:test-screenshots [tr] App Store screenshot set in a locale (default tr)
174
+
175
+ The scenario-tag form still works and is not deprecated - each command above is
176
+ an alias for it.
177
+
178
+ /multi-agent:test "dark mode" | "accessibility" | "dynamic type" | "screenshot <lang>"
179
+
180
+ `store-ready` is NOT a UI test: it validates a built package, on iOS and Android,
181
+ through three gates per platform, and lives at /multi-agent:store-ready. The old
182
+ /multi-agent:test "store-ready" [path] tag still works and hands off there.
164
183
 
165
184
  Uses xcrun simctl / adb (native, no external app needed).
166
185
  Booted simulator/emulator required. Auto-detects bundle ID from project.
@@ -362,6 +381,14 @@ Post-Hoc & Side-Channel:
362
381
  /multi-agent:search Task log'larında akıllı arama; --semantic triage corpus'unu sorgular
363
382
  /multi-agent:scan Skill güvenlik taraması (tiered pattern catalog)
364
383
  /multi-agent:refactor Uyarlanmış best-practice + bug avı + upstream-drift + dev-toolkit MCP araştırması -> tek plan, onay, dev + sync
384
+ /multi-agent:store-ready [repo] [--archive=|--ipa=|--aab=|--apk=] [--skip-sweep] Yükleme öncesi store hazırlığı,
385
+ iOS + Android, yalnızca lokal. Platform başına 3 simetrik kapı: statik paket denetimi,
386
+ store'un kendi doğrulayıcısı, kaynağa karşı politika incelemesi. Artı çalışan-app sweep'i.
387
+ Atlanan kapı asla pass sayılmaz. Sadece doğrular, asla yüklemez.
388
+ /multi-agent:testflight-validation [repo] [--ipa=|--archive=] :store-ready'nin iOS'a sabitlenmiş alias'ı; hedef
389
+ TestFlight olduğunda akla gelen isim olduğu için korunuyor. Aynı 3 kapı, tek implementasyon.
390
+ /multi-agent:ios-coding-standard [modül] Bir iOS modülünü 99 kurallık kodlama-standardı registry'sine göre denetler -> düzeltme
391
+ planı + tek sayfalık onboarding özeti -> dev / dev-local'e devreder. Read-only, kaynağı hiç düzenlemez.
365
392
 
366
393
  Setup & Maintenance:
367
394
 
@@ -399,11 +426,22 @@ Rutinler (kendi tekrar eden işlerin):
399
426
  UI Testing (standalone - pipeline fazlarından bağımsız):
400
427
 
401
428
  /multi-agent:test Tam simulator testi (tüm ekran screenshot'ları)
402
- /multi-agent:test "dark mode" Dark mode bug testi
403
- /multi-agent:test "accessibility" Erişilebilirlik denetimi (label/tap-target/kontrast)
404
- /multi-agent:test "dynamic type" Büyük metin boyutu testi
405
- /multi-agent:test "screenshot tr" App Store screenshot seti (Türkçe locale)
406
- /multi-agent:test "store-ready" App Store guideline pre-flight kontrolü
429
+
430
+ Sabit-senaryo komutları - tırnak gerekmez, `test-` ile autocomplete'e düşer:
431
+
432
+ /multi-agent:test-dark-mode Dark mode bug testi
433
+ /multi-agent:test-accessibility Erişilebilirlik denetimi (label/tap-target/kontrast)
434
+ /multi-agent:test-dynamic-type Büyük metin boyutu testi
435
+ /multi-agent:test-screenshots [tr] Belirtilen dilde App Store screenshot seti (default tr)
436
+
437
+ Senaryo etiketli form çalışmaya devam eder, kaldırılmadı - yukarıdaki komutların
438
+ her biri onun alias'ı.
439
+
440
+ /multi-agent:test "dark mode" | "accessibility" | "dynamic type" | "screenshot <dil>"
441
+
442
+ `store-ready` bir UI testi DEĞİL: üretilmiş paketi platform başına üç kapıdan
443
+ geçirerek doğrular, iOS + Android, ve /multi-agent:store-ready altında. Eski
444
+ /multi-agent:test "store-ready" [path] etiketi çalışır ve oraya devreder.
407
445
 
408
446
  xcrun simctl / adb kullanır (harici app gerekmez).
409
447
  Booted simulator/emulator şart. Bundle ID proje'den otomatik algılanır.
@@ -458,7 +496,7 @@ Temel Özellikler:
458
496
  Multi-Repo Repo başına worktree, repo başına identity, commit öncesi entegrasyon build'i
459
497
  Identity Routing Repo origin URL'sinden git kimliği seçimi (kurumsal vs kişisel)
460
498
  Issue Safety Issue'lar asla auto-close edilmez (GitHub + Jira için 4 onay gerekir)
461
- Store Compliance /multi-agent:test "store-ready" - iOS için 17 kurallık audit (ITMS / Privacy Manifest /
499
+ Store Compliance /multi-agent:test "store-ready" - iOS için 18 kurallık audit (ITMS / Privacy Manifest /
462
500
  code signing / debug-tool leak / IPv6 / SDK list / vb.) + Android için 21 kurallık audit
463
501
  Bilingual EN + TR - outputLanguage assistant açıklamasını değiştirir; promptLanguage en kilitli
464
502
 
@@ -116,7 +116,7 @@ These are the RECOMMENDED key names. When creating NEW keys, use these. But exis
116
116
 
117
117
  > Multi-agent setup onboards **both** Figma tokens because the pipeline's 3-tier Figma access chain (see `$HOME/.claude/rules/figma-pipeline.md`) uses them in priority order: Tier 1 = MCP (`figma_mcp`), Tier 2 = REST PAT (`figma`), Tier 3 = user screenshot fallback. Missing either token forces a downshift; missing both leaves Tier 3 as the only path. The Tier 2 logical key is `figma`, not `figma_pat`: `figma_pat` is the pre-v13.6 name that `migrate-prefs.mjs` consolidates away, and writing a new mapping under it means the next migration deletes it.
118
118
 
119
- > The four App Store Connect entries are **iOS-only and optional**: skip them all and the pipeline still works, it just reports Gate 2 of `/multi-agent:testflight-validation` as `SKIPPED` (never as a pass). They mirror the Figma 3-tier shape - Tier 1 = API key (`appstore_connect_key_id` + `appstore_connect_issuer_id`), Tier 2 = Apple ID + app-specific password (`appstore_connect_apple_id` + `appstore_connect_password_item`), Tier 3 = nothing configured. **Offer Tier 2 first when the user says they cannot create an API key**: creating one needs an Admin or App Manager role in App Store Connect, while an app-specific password is generated by the account holder at `appleid.apple.com` with no team permission at all. Two of these hold identifiers rather than secrets (key id, issuer id) and one holds a keychain ITEM NAME, not a password - they still go through the mapping layer so every credential is read the same way. Onboarding mechanics in Step 3b.
119
+ > The four App Store Connect entries are **iOS-only and optional**: skip them all and the pipeline still works, it just reports Gate 2 of `/multi-agent:store-ready` as `SKIPPED` (never as a pass). They mirror the Figma 3-tier shape - Tier 1 = API key (`appstore_connect_key_id` + `appstore_connect_issuer_id`), Tier 2 = Apple ID + app-specific password (`appstore_connect_apple_id` + `appstore_connect_password_item`), Tier 3 = nothing configured. **Offer Tier 2 first when the user says they cannot create an API key**: creating one needs an Admin or App Manager role in App Store Connect, while an app-specific password is generated by the account holder at `appleid.apple.com` with no team permission at all. Two of these hold identifiers rather than secrets (key id, issuer id) and one holds a keychain ITEM NAME, not a password - they still go through the mapping layer so every credential is read the same way. Onboarding mechanics in Step 3b.
120
120
 
121
121
  **1c. Resolution logic (per service):**
122
122
 
@@ -0,0 +1,340 @@
1
+ ---
2
+ description: "Pre-submission store readiness for a built package, iOS and Android, local-only. Three symmetric gates per platform: a static package audit, the store's own authoritative validation, and a policy review against repo source. Separate verdict per gate, a skipped gate never counted as a pass. Validates only, never uploads. Use when a build is about to go to TestFlight or a Play track, or when a submission was rejected and the reason is not obvious."
3
+ description-tr: "Üretilmiş paketin yükleme öncesi store hazırlığı, iOS + Android, yalnızca lokal. Platform başına üç simetrik kapı: statik paket denetimi, store'un kendi doğrulayıcısı, ve kaynağa karşı politika incelemesi. Kapı başına ayrı verdict, atlanan kapı asla pass sayılmaz. Sadece doğrular, asla yüklemez."
4
+ argument-hint: "[repo] - empty = pick; repo name or path; --ipa= | --archive= | --aab= | --apk=; --skip-sweep; --resume"
5
+ allowed-tools: Agent, Bash, Read, Write, Edit, Glob, Grep, TaskCreate, TaskUpdate, AskUserQuestion, Skill, mcp__dev-toolkit__ios_app_store_audit, mcp__dev-toolkit__ios_export_ipa, mcp__dev-toolkit__ios_testflight_validate, mcp__dev-toolkit__ios_xcodebuild, mcp__dev-toolkit__ios_xcresult, mcp__dev-toolkit__android_apk_audit, mcp__dev-toolkit__ios_screenshot, mcp__dev-toolkit__ios_get_ui_tree, mcp__dev-toolkit__ios_set_appearance, mcp__dev-toolkit__ios_set_content_size, mcp__dev-toolkit__android_screenshot, mcp__dev-toolkit__android_get_ui_tree, mcp__dev-toolkit__android_set_dark_mode, mcp__dev-toolkit__android_set_font_scale
6
+ ---
7
+
8
+ # /multi-agent:store-ready - pre-submission validation, iOS + Android
9
+
10
+ Catch, before you upload, what App Store Connect or the Play Console would send
11
+ back after you do.
12
+
13
+ **Local-only.** No commits, no push, no PR, no channels unless you ask at the end.
14
+ A worktree, when one is needed, exists only to archive without touching your
15
+ working tree.
16
+
17
+ **It never uploads.** iOS runs `--validate-app`, never `--upload-app`. Android
18
+ never commits a Play edit. A validation run must not be able to ship a build by
19
+ accident.
20
+
21
+ **Input**: $ARGUMENTS
22
+
23
+ ## Why three gates, and why the same three on both platforms
24
+
25
+ Each gate sees something the others structurally cannot, and reporting one of them
26
+ as "the check" is how a build passes locally and gets rejected anyway. The shapes
27
+ are the same on iOS and Android because the failure modes are: a malformed package,
28
+ a package the store itself refuses, and a policy a human enforces.
29
+
30
+ | Gate | Sees | Blind to |
31
+ |---|---|---|
32
+ | **1. Static** | package structure, manifests, signing, declared APIs and SDKs | anything depending on the store account |
33
+ | **2. Authoritative** | what the store's own validator says about this exact binary | written policy - no validator reads it |
34
+ | **3. Policy** | consent flows, deletion paths, purchase routing, disclosures | anything not visible in source |
35
+
36
+ ### Gate matrix
37
+
38
+ | Gate | iOS | Android |
39
+ |---|---|---|
40
+ | 1 Static | `ios_app_store_audit({archive_path, rules: "all"})` - 18 rules with real ITMS codes. Needs an `.xcarchive`. Reference: `apple-archive-compliance` skill | `android_apk_audit` plus the `google-play-compliance` skill's 21 rules: `bundletool validate` + manifest dump, `aapt2 dump badging`, `apksigner verify`, ABI / native scan. Needs an `.aab` (an `.apk` narrows it, see Step 3) |
41
+ | 2 Authoritative | `ios_testflight_validate({ipa_path, platform: "ios", <credentials>})` → `xcrun altool --validate-app`. Needs an `.ipa` + credentials | **No client shipped.** Play's authoritative check exists only server-side, through a Publishing API draft edit that is validated and then abandoned. The pipeline has no tool for it, so this gate reports `SKIPPED (no local Play validator)` and the report says so. Do not substitute `bundletool validate` - that is Gate 1 |
42
+ | 3 Policy | `app-store-review` skill vs repo source | `play-store-review` skill vs repo source |
43
+
44
+ Gate 2's asymmetry is real and is reported as an asymmetry, not smoothed over. On
45
+ iOS it is the only gate that catches a version+build pair already used - the most
46
+ common wasted upload. On Android nothing local reproduces it, so an Android run
47
+ clears at most 2 of 3 gates and must never print `passed`.
48
+
49
+ ## Step 0 - parse input, detect platform
50
+
51
+ | Input | Meaning |
52
+ |---|---|
53
+ | (empty) | ask which repo (Step 1) |
54
+ | `my-app` or a path | that repo |
55
+ | `--archive=<path>` | iOS, build supplied; all three gates can run |
56
+ | `--ipa=<path>` | iOS, build supplied; Gate 1 reports `SKIPPED (needs .xcarchive)` |
57
+ | `--aab=<path>` | Android, build supplied; Gate 1 + 3 run |
58
+ | `--apk=<path>` | Android; Gate 1 runs the subset that does not need a bundle, and says which rules it could not apply |
59
+ | `--skip-sweep` | skip Step A, when no simulator / emulator is available or only the package matters |
60
+ | `--resume` | continue the last run from its state file |
61
+
62
+ Platform detection when no build flag is given:
63
+
64
+ ```
65
+ cwd or repo contains .xcodeproj / .xcworkspace / Package.swift -> iOS
66
+ cwd or repo contains build.gradle / build.gradle.kts -> Android
67
+ both -> ask which
68
+ neither -> halt: "store-ready needs an iOS or Android project"
69
+ ```
70
+
71
+ State lives at `$HOME/.claude/logs/multi-agent/<task_id>/agent-state.json` with
72
+ `taskId = SR-<repo>-<yyyymmddHHMM>`. Register phases with the tracker
73
+ (`$HOME/.claude/multi-agent-refs/tracker-contract.md`) so `:resume` and `:status`
74
+ work like any other run.
75
+
76
+ ## Step 1 - pickers (native, always)
77
+
78
+ Use `AskUserQuestion` for every step - never a numbered text menu. Questions and
79
+ descriptions render in `prefs.global.outputLanguage`; `label` and `header` stay
80
+ English, per `$HOME/.claude/multi-agent-refs/picker-contract.md`. Print the
81
+ `Step <i>/<n>: <what this decides>` breadcrumb for each.
82
+
83
+ 1. **Repo** - from `prefs.projects` matching the detected platform. A single match
84
+ auto-resolves (say so in the breadcrumb, do not silently skip the step).
85
+ 2. **Branch** - the branch to validate. Resolution order:
86
+ - `git fetch --prune` first, capturing **stderr**. **If the fetch fails, do not
87
+ silently fall back to a cached ref**, and **classify before naming a cause** -
88
+ the same rule as the `/multi-agent:dev` remote gate:
89
+
90
+ | stderr contains | Cause | Remedy |
91
+ |---|---|---|
92
+ | `could not read Password`, `Authentication failed`, `403` | credential | store the PAT in the credential helper or switch the remote to SSH. **A VPN cannot fix this**, and the base ref being stale is unrelated to what broke - do not offer the cached-ref fallback. |
93
+ | `Could not resolve host`, `Operation timed out`, `Connection refused` | network | retry / continue on the cached ref with an explicit warning / switch remote / abort, per `$HOME/.claude/multi-agent-refs/rules.md` |
94
+ | `Repository not found`, `404` | wrong remote | show `git remote -v` and ask |
95
+
96
+ Always print the observed stderr line next to the classification. Asserting
97
+ `unreachable (VPN/DNS)` for a missing-credential error that returns in under a
98
+ second sends the user to fix something that was never broken.
99
+ - Offer the current branch, the default branch, and any `release/*` /
100
+ `tkdevelop/*` heads.
101
+ 3. **Mode** - how the build is obtained:
102
+ - `Supply a build` (Mode B, default) - fastest, no signing needed in-run.
103
+ - `Build from this branch` (Mode A) - iOS needs a distribution certificate and
104
+ profile in the keychain; Android needs the release signing config. Takes as
105
+ long as a real release build.
106
+
107
+ ## Step 2 - pre-flight, before anything expensive
108
+
109
+ Report every line; a missing prerequisite is a halt, not a warning.
110
+
111
+ **iOS:**
112
+
113
+ ```bash
114
+ xcrun --find altool >/dev/null 2>&1 || echo "MISSING: altool (install Xcode)"
115
+ xcodebuild -version | head -1
116
+ ```
117
+
118
+ Then resolve credentials, and **state which tier is active in the report**:
119
+
120
+ | Tier | Source | Effect |
121
+ |---|---|---|
122
+ | 1 | ASC API key - key id + issuer id from the keychain via `prefs.global.keychainMapping`, `.p8` at `~/.appstoreconnect/private_keys/AuthKey_<keyId>.p8` | Gate 2 runs |
123
+ | 2 | Apple ID + app-specific password, referenced as a keychain item | Gate 2 runs |
124
+ | 3 | neither | **Gate 2 reports `SKIPPED`, and the run says so in the verdict line** |
125
+
126
+ Multi-provider accounts need `--provider-public-id`. When it is not in prefs, run
127
+ `ios_testflight_validate({list_providers: true})` once and ask which provider.
128
+
129
+ **Android:**
130
+
131
+ ```bash
132
+ command -v bundletool >/dev/null || echo "MISSING: bundletool"
133
+ command -v aapt2 >/dev/null || echo "MISSING: aapt2 (Android SDK build-tools)"
134
+ command -v apksigner >/dev/null || echo "MISSING: apksigner (Android SDK build-tools)"
135
+ ```
136
+
137
+ There is no credential tier to resolve: Gate 2 has no local client, so it is
138
+ `SKIPPED` by construction rather than by configuration. Say which of the two it is
139
+ - a user who thinks a credential would unlock it will go looking for one.
140
+
141
+ Credentials come from `/multi-agent:setup`; never prompt for a secret value in
142
+ chat.
143
+
144
+ ## Step A - running-app sweep (unless `--skip-sweep`)
145
+
146
+ The gates read a package; this reads the app. A build can be structurally perfect
147
+ and still ship an unreadable screen, so the sweep stays part of store readiness
148
+ rather than being a separate errand.
149
+
150
+ Requires a booted simulator / emulator. When none is available, report
151
+ `Sweep: SKIPPED (no booted device)` and continue to the gates - never halt the
152
+ package validation for it, and never silently omit the line.
153
+
154
+ Delegate to the UI Bug Hunter flow (`$HOME/.claude/commands/sim-test.md`) for the
155
+ mechanics, running the light + dark + large-text passes over every screen. Merge
156
+ its findings into the single report at Step 7, severity-grouped alongside the gate
157
+ findings.
158
+
159
+ ## Step 3 - obtain the build
160
+
161
+ ### Mode B - a build you supply
162
+
163
+ - **iOS `.xcarchive`** → Gate 1 runs on it. To reach Gate 2 the archive must be
164
+ exported, so run `ios_export_ipa` (see Mode A for the signing inputs).
165
+ - **iOS `.ipa` only** → **Gate 1 is `SKIPPED (needs .xcarchive)`.** The static audit
166
+ reads archive structure an `.ipa` does not carry. Do not present a two-gate run as
167
+ a full pass; say which gate did not run and why, and offer to re-run with the
168
+ archive.
169
+ - **Android `.aab`** → Gate 1 runs in full.
170
+ - **Android `.apk` only** → Gate 1 runs the rules that do not need a bundle and
171
+ **lists the rules it could not apply**. An `.apk` cannot answer bundle-level
172
+ questions (per-ABI splits, dynamic features, Play App Signing expectations).
173
+
174
+ When no path is given, pick the newest artifact and print which one you picked:
175
+
176
+ ```
177
+ iOS: newest .xcarchive under ~/Library/Developer/Xcode/Archives/**
178
+ Android: newest .aab under **/build/outputs/bundle/**/*.aab
179
+ ```
180
+
181
+ Never validate an artifact whose provenance you did not state. "The newest archive"
182
+ is a guess the user must be able to correct.
183
+
184
+ ### Mode A - build from the branch
185
+
186
+ 1. Worktree at `{projectRoot}/{worktreeBasePath}/{taskId}` on the chosen branch.
187
+ **Never under `$HOME`**, never a direct checkout of the main working tree.
188
+ 2. Resolve the scheme / module and workspace / project from prefs; ask if ambiguous.
189
+ 3. Build:
190
+ - **iOS**: `ios_xcodebuild({workspace|project, scheme, action: "archive", configuration: "Release", destination: "generic/platform=iOS"})`.
191
+ Note the destination: the simulator default would produce an archive that
192
+ cannot be exported for distribution.
193
+ - **Android**: `./gradlew bundleRelease` (or the release variant the module
194
+ declares). A debug-signed bundle fails Gate 1 signing rules for the wrong
195
+ reason - if no release signing config resolves, halt and say so rather than
196
+ auditing a debug artifact.
197
+ 4. **iOS export**:
198
+ `ios_export_ipa({archive_path, output_dir, method: "app-store-connect", team_id, provisioning_profiles?, signing_style?})`.
199
+ Leave `allow_provisioning_updates` off unless the user asks: it lets xcodebuild
200
+ create or modify profiles in the developer account, which a validation run has no
201
+ business doing.
202
+ 5. A failed build or export halts with the parsed errors. The usual iOS causes are a
203
+ missing distribution certificate, a profile that does not match the bundle ID, or
204
+ `signing_style: "manual"` with no `provisioning_profiles` map.
205
+
206
+ ## Step 4 - Gate 1, static package audit
207
+
208
+ - **iOS**: `ios_app_store_audit({archive_path, rules: "all"})`. Consult the
209
+ `apple-archive-compliance` skill for what each rule means.
210
+
211
+ Needs `@mmerterden/dev-toolkit-mcp` ≥ v2.9.0, which provides the tool. When the
212
+ MCP server is not registered, the same 18 rules run directly from the package:
213
+
214
+ ```bash
215
+ node -e "import('@mmerterden/dev-toolkit-mcp/tools/ios-app-store-audit/index.js').then(m => m.runAudit({ archivePath: '<path>', rules: 'all' }).then(r => console.log(JSON.stringify(r))))"
216
+ ```
217
+
218
+ Use the fallback only when the tool is genuinely absent, and say in the report
219
+ which path ran - a rule set that silently differed between two invocations is
220
+ worse than a missing gate.
221
+ - **Android**: `android_apk_audit` on the artifact, plus the
222
+ `google-play-compliance` skill's 21 rules - `bundletool validate` and manifest
223
+ dump, `aapt2 dump badging`, `apksigner verify`, ABI / native scan.
224
+
225
+ `error` findings are blocking; `warning` is advisory. Group by severity and keep
226
+ each finding's ITMS / Play policy code - Gate 2 may return the same code on iOS,
227
+ and seeing it in both places tells the user it is real rather than a heuristic.
228
+
229
+ ## Step 5 - Gate 2, the store's own validation
230
+
231
+ **iOS**: `ios_testflight_validate({ipa_path, platform: "ios", <credential args>})`.
232
+ Render the verdict exactly as returned:
233
+
234
+ - `PASS` - Apple accepted the binary for delivery.
235
+ - `FAIL` - list each issue with its ITMS code, the mapped guideline, and the hint.
236
+ - `SKIPPED` - print the reason. **Never render this as a pass.**
237
+
238
+ Gate 2 is the only gate that catches a build number already used - so when it
239
+ fails on that, say so plainly and name the next free build number.
240
+
241
+ **Android**: report `SKIPPED (no local Play validator)` with one line on why: the
242
+ authoritative check is a Play Publishing API draft edit, the pipeline ships no
243
+ client for it, and no local tool substitutes. `bundletool validate` is Gate 1 and
244
+ reporting it here would fake a cleared gate.
245
+
246
+ ## Step 6 - Gate 3, policy review
247
+
248
+ Load the platform's review skill and review the repo against it. This is the gate
249
+ that catches what a human reviewer rejects, so it reads source, not the binary.
250
+
251
+ **iOS** - `app-store-review`:
252
+
253
+ | Area | Evidence to gather |
254
+ |---|---|
255
+ | Purpose strings | every `NS*UsageDescription` in Info.plist - present, specific, user-facing, and matching what the code actually does with the data |
256
+ | Privacy manifest | `PrivacyInfo.xcprivacy` exists, declares required-reason APIs, and matches the SDKs actually linked |
257
+ | Tracking | if any tracking API or SDK is present, an ATT prompt exists and runs before collection |
258
+ | Account deletion | if the app creates accounts, an in-app deletion path exists (guideline 5.1.1(v)) |
259
+ | Privacy policy | reachable in-app and in the metadata |
260
+ | IAP | anything unlocking features goes through StoreKit, with no external purchase path |
261
+ | Sign in with Apple | present when a third-party social login is offered |
262
+
263
+ **Android** - `play-store-review`:
264
+
265
+ | Area | Evidence to gather |
266
+ |---|---|
267
+ | Permissions | every `uses-permission` justified by a feature, no sensitive permission without its declaration form |
268
+ | Data safety | the declared data-safety answers match what the code collects and transmits |
269
+ | Target API level | meets the current Play requirement for new releases |
270
+ | Privacy policy | reachable in-app and in the listing |
271
+ | Billing | anything unlocking features goes through Play Billing, with no external purchase path |
272
+ | Account deletion | if the app creates accounts, an in-app deletion path exists, plus the web deletion URL Play requires |
273
+ | Content rating | the questionnaire answers match the app's actual content |
274
+ | Signing | Play App Signing configured, upload key distinct from the app signing key |
275
+
276
+ For each: `pass` / `fail` / `not-applicable` with the evidence path that justifies
277
+ it. `not-applicable` needs a reason - an unexamined area is not a pass.
278
+
279
+ ## Step 7 - report
280
+
281
+ Write to `~/StoreChecks/<platform>-<repo>-<branch>-<timestamp>/report.md` and print
282
+ a summary.
283
+
284
+ ```
285
+ Verdict: <N> of 3 gates cleared[, <M> skipped]
286
+ Platform:<ios|android>
287
+ Build: <artifact path> · <bundle id / applicationId> <version> (<build>)
288
+ Auth: tier <1|2|none> · <method> (iOS only)
289
+ Sweep: <n> findings | SKIPPED (<reason>)
290
+
291
+ Gate 1 static audit PASS | FAIL (<n> blocking, <n> advisory) | SKIPPED (<reason>)
292
+ Gate 2 store validation PASS | FAIL (<n> issues) | SKIPPED (<reason>)
293
+ Gate 3 policy review PASS | FAIL (<n> findings) | <n> not-applicable
294
+
295
+ Blocking - fix before uploading
296
+ [ITMS-90683] Info.plist: NSCameraUsageDescription missing
297
+ guideline 5.1.1 Data Collection and Storage
298
+ <hint>
299
+ <file:line>
300
+
301
+ Advisory
302
+ ...
303
+
304
+ Not run
305
+ Gate 2: no local Play validator - authoritative check is server-side only
306
+ ```
307
+
308
+ Rules for the report:
309
+
310
+ - A skipped gate is never folded into the pass count. The verdict line states the
311
+ skip. An Android run therefore reads `2 of 3 gates cleared, 1 skipped` at best.
312
+ - Every blocking finding carries a file path or a store code. A finding the user
313
+ cannot act on is noise.
314
+ - Humanize via `--lang en` by default (`promptLanguage` is locked to `"en"`); pass
315
+ `--lang=tr` explicitly to opt into Turkish.
316
+ - No AI or assistant attribution anywhere, per
317
+ `$HOME/.claude/rules/git-conventions.md`.
318
+ - Real newlines, no HTML entities, per
319
+ `$HOME/.claude/multi-agent-refs/rules.md "External System Outputs"`.
320
+
321
+ ## Step 8 - offer the next action, do not take it
322
+
323
+ Print, and stop:
324
+
325
+ - the exact upload command for when the gates are clear, so uploading stays an
326
+ explicit human act:
327
+ - iOS: `xcrun altool --upload-app ...`
328
+ - Android: the Play Console upload, or the `gradle publish` task the project
329
+ declares - never run it
330
+ - `/multi-agent:store-ready --resume` to re-run after fixes
331
+ - `/multi-agent:channels` to land the findings in Jira / Confluence / Wiki / PR
332
+ - `/multi-agent:fix-bug` when Gate 3 produced code-level findings
333
+
334
+ Never upload, never commit a Play edit, never bump the build number, never commit.
335
+
336
+ ## Related surfaces
337
+
338
+ `/multi-agent:testflight-validation` is a thin alias onto this command, kept so the
339
+ iOS-only name keeps working; it resolves here with the platform pinned to iOS.
340
+ `/multi-agent:test "store-ready"` also resolves here. There is one implementation.