@mmerterden/multi-agent-pipeline 12.11.0 → 13.1.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.
- package/CHANGELOG.md +179 -0
- package/README.md +24 -7
- package/index.js +5 -2
- package/install/_codex-agents.mjs +211 -0
- package/install/_codex-instructions.mjs +33 -0
- package/install/_managed-block.mjs +99 -0
- package/install/codex.mjs +478 -0
- package/install/copilot.mjs +34 -80
- package/install/index.mjs +25 -9
- package/install/templates/codex-instructions.md +45 -0
- package/package.json +5 -3
- package/pipeline/claude-md-template.md +1 -0
- package/pipeline/commands/multi-agent/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/dev/SKILL.md +52 -6
- package/pipeline/commands/multi-agent/dev-local/SKILL.md +21 -0
- package/pipeline/commands/multi-agent/finish/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/language/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/setup/SKILL.md +69 -2
- package/pipeline/commands/multi-agent/sync/SKILL.md +128 -5
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +219 -0
- package/pipeline/commands/multi-agent/update/SKILL.md +7 -4
- package/pipeline/multi-agent-refs/_input-parser.md +1 -1
- package/pipeline/multi-agent-refs/component-dispatch.md +40 -7
- package/pipeline/multi-agent-refs/cross-cli-contract.md +51 -17
- package/pipeline/multi-agent-refs/features/model-fallback.md +29 -0
- package/pipeline/multi-agent-refs/features/review-multi-repo.md +1 -1
- package/pipeline/multi-agent-refs/phases/log-format.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +43 -2
- package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +24 -1
- package/pipeline/multi-agent-refs/phases/phase-3-dev.md +32 -0
- package/pipeline/multi-agent-refs/phases/phase-4-review.md +62 -5
- package/pipeline/multi-agent-refs/progress-contract.md +1 -1
- package/pipeline/multi-agent-refs/tracker-contract.md +17 -1
- package/pipeline/schemas/prefs.schema.json +296 -62
- package/pipeline/schemas/reviewer-output.schema.json +1 -1
- package/pipeline/schemas/triage-output.schema.json +1 -1
- package/pipeline/scripts/cost-table.json +15 -1
- package/pipeline/scripts/phase0-exit-gate.mjs +185 -0
- package/pipeline/scripts/smoke-cross-cli-behavior.sh +25 -10
- package/pipeline/scripts/uninstall.mjs +105 -9
- package/pipeline/scripts/update-check.sh +2 -1
- package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +21 -0
- package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +21 -0
- package/pipeline/skills/shared/core/multi-agent-language/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +48 -1
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +87 -6
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +120 -0
|
@@ -20,6 +20,7 @@ When invoked, it synchronizes all targets in order. It detects what changed, upd
|
|
|
20
20
|
|---|-------|-----|-----|
|
|
21
21
|
| 1 | Claude Code (source of truth) | `~/.claude/commands/multi-agent.md` + `~/.claude/commands/multi-agent/` + `~/.claude/agents/` + `~/.claude/scripts/` | source |
|
|
22
22
|
| 2 | Copilot CLI | `~/.copilot/copilot-instructions.md` + `~/.copilot/skills/` | <- from Claude |
|
|
23
|
+
| 2b | Codex CLI | `~/.codex/AGENTS.md` + `~/.codex/skills/multi-agent/` + `~/.codex/multi-agent-refs/` + `~/.codex/agents/*.toml` | <- from Claude (path-rewritten) |
|
|
23
24
|
| 3 | multi-agent-pipeline repo | `~/multi-agent-pipeline/pipeline/` | <- from Claude (genericized) |
|
|
24
25
|
| 4 | Website | `{owner}/{website-host}` | <- version + features |
|
|
25
26
|
| 5 | dev-toolkit MCP server | resolved from `prefs.global.devToolkit` or the `mcpServers` registration | own repo: gate, commit, publish |
|
|
@@ -30,7 +31,8 @@ Run all steps automatically:
|
|
|
30
31
|
|
|
31
32
|
```
|
|
32
33
|
Step 1: DETECT Compare timestamps, find stale targets
|
|
33
|
-
Step 2: COPILOT Claude Code -> Copilot CLI (instructions +
|
|
34
|
+
Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 43 sub-command skills)
|
|
35
|
+
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill + 43 specs as refs + 8 agent TOML)
|
|
34
36
|
Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub)
|
|
35
37
|
Step 3d: DEV-TOOLKIT Companion MCP server -> detect movement, ship gates, commit + publish
|
|
36
38
|
Step 4: WEBSITE Version + phase/model counts -> {website-host} (i18n + projects.ts)
|
|
@@ -93,6 +95,41 @@ If nothing is stale -> report "All targets up to date" and stop.
|
|
|
93
95
|
- `~/.claude/settings.json`
|
|
94
96
|
|
|
95
97
|
|
|
98
|
+
## Codex Sync (Step 2b)
|
|
99
|
+
|
|
100
|
+
This step does **not** hand-copy files. The Codex tree is a *transform* of the Claude
|
|
101
|
+
tree, not a mirror: the 43 sub-command specs become reference files (Codex silently
|
|
102
|
+
truncates its skills block - see `cross-cli-contract.md` 2.6), every reference to a
|
|
103
|
+
CLI-owned tree is retargeted (`agents/<persona>.md` becomes `.toml`, the dispatcher
|
|
104
|
+
becomes the router skill), the 8 personas are regenerated as TOML with a model +
|
|
105
|
+
reasoning-effort map, and shared state (`logs/`, prefs, `knowledge/`) is deliberately
|
|
106
|
+
left under `~/.claude`.
|
|
107
|
+
|
|
108
|
+
That transform lives in `install/codex.mjs` and is gate-locked by
|
|
109
|
+
`smoke-codex-install.sh`. Describing it again in prose would give the pipeline two
|
|
110
|
+
definitions of the same thing, and the prose one would rot. So the step runs the
|
|
111
|
+
installer:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cd "$HOME/multi-agent-pipeline" && node install.js --codex
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Verify:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
ls -1 "$HOME/.codex/skills" | grep -c '^multi-agent$' # want 1
|
|
121
|
+
find "$HOME/.codex/multi-agent-refs/commands" -name SKILL.md | wc -l # want the command count
|
|
122
|
+
grep -rhoE '(\$HOME|~)/\.claude/(agents|scripts|lib|schemas|commands|multi-agent-refs|rules)' \
|
|
123
|
+
"$HOME/.codex/skills" "$HOME/.codex/multi-agent-refs" | sort -u # want empty
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
MCP is registered by the installer via `codex mcp add dev-toolkit` (idempotent,
|
|
127
|
+
skipped with a warning when `codex` is absent). Never hand-edit
|
|
128
|
+
`~/.codex/config.toml` - Codex owns it. Run this AFTER the REPO step, since the
|
|
129
|
+
installer reads the repo tree.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
96
133
|
## Dev-Toolkit Sync (Step 3d)
|
|
97
134
|
|
|
98
135
|
The companion MCP server (`dev-toolkit-mcp`) is its own repo with its own registry. Pipeline skills call its tools and several declare a minimum version, so when it moves it has to ship.
|
|
@@ -114,13 +151,19 @@ When the toolkit ships its own gate script (`npm run gates` / `scripts/gates.sh`
|
|
|
114
151
|
|
|
115
152
|
**Version bump**: patch for fixes and docs, minor for a new tool, major for a removed or renamed tool.
|
|
116
153
|
|
|
117
|
-
**Ship**: commit with that repo's own convention, tag `v<version>`, push with `--tags`, then publish to the registry from `publishConfig` using a throwaway userconfig - never edit `~/.npmrc`, never a bare `npm publish`. The token depends on the registry: `npm.pkg.github.com` needs a GitHub PAT with `write:packages
|
|
154
|
+
**Ship**: commit with that repo's own convention, tag `v<version>`, push with `--tags`, then publish to the registry from `publishConfig` using a throwaway userconfig - never edit `~/.npmrc`, never a bare `npm publish`. The token depends on the registry AND on the package scope: the registry picks the credential type, the scope picks the account. `npm.pkg.github.com` needs a **Classic** GitHub PAT with `write:packages`; `registry.npmjs.org` needs the `npm` key. Resolving on host alone misroutes on any machine with a work and a personal GitHub identity - prefer a scope-specific mapping (`github_<scope>`) and fall back to the generic `github` key only when there is one identity.
|
|
118
155
|
|
|
119
156
|
```bash
|
|
120
157
|
NPMRC=$(mktemp); trap 'rm -f "$NPMRC"' EXIT
|
|
121
158
|
REG=$(node -p "require('./package.json').publishConfig?.registry || 'https://registry.npmjs.org'")
|
|
122
159
|
HOST=${REG#https://}; HOST=${HOST%/}
|
|
123
|
-
|
|
160
|
+
SCOPE=$(node -p "(require('./package.json').name.match(/^@([^/]+)/)||[])[1] || ''")
|
|
161
|
+
case "$HOST" in
|
|
162
|
+
npm.pkg.github.com*) KEY=github; [ -n "$SCOPE" ] && KEY="github_$SCOPE" ;;
|
|
163
|
+
*) KEY=npm ;;
|
|
164
|
+
esac
|
|
165
|
+
# Fall back to the generic key when no scope-specific mapping exists.
|
|
166
|
+
bash "$HOME/.copilot/lib/credential-store.sh" get "$KEY" >/dev/null 2>&1 || KEY=github
|
|
124
167
|
TOKEN=$(bash "$HOME/.claude/lib/credential-store.sh" get "$KEY")
|
|
125
168
|
[ -n "$TOKEN" ] || echo "ABORT: no '$KEY' token - onboard it via /multi-agent:setup before publishing"
|
|
126
169
|
printf '%s\n' "registry=$REG" "//$HOST/:_authToken=$TOKEN" > "$NPMRC"
|
|
@@ -167,24 +210,27 @@ When invoked with the `release` argument:
|
|
|
167
210
|
7. DEV-TOOLKIT Ship the companion MCP server if it moved (Step 3d gates, then publish)
|
|
168
211
|
8. WEBSITE Version + features -> {website-host}
|
|
169
212
|
9. COPILOT Copilot CLI instructions + skills sync
|
|
213
|
+
9b. CODEX Codex CLI router skill + refs + agent TOML (node install.js --codex)
|
|
170
214
|
10. Report Summary: version, touched repos, deploy status
|
|
171
215
|
```
|
|
172
216
|
|
|
173
217
|
|
|
174
218
|
## Sub-Command Sync (Claude Code <-> Copilot CLI Skills)
|
|
175
219
|
|
|
220
|
+
> Codex takes the Step 2b path instead; see that section.
|
|
221
|
+
|
|
176
222
|
| Claude Code | Copilot CLI |
|
|
177
223
|
|-------------|-------------|
|
|
178
224
|
| `~/.claude/commands/multi-agent/{cmd}.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
|
|
179
225
|
|
|
180
|
-
**
|
|
226
|
+
**43 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
|
|
181
227
|
|
|
182
228
|
```
|
|
183
229
|
analysis, analysis-resolve, autopilot, build-optimize, channels, create-jira, design-check, dev,
|
|
184
230
|
dev-autopilot, dev-local, dev-local-autopilot, diff-explain, finish, forget, garbage-collect,
|
|
185
231
|
help, issue, jira, kill, language, local,
|
|
186
232
|
local-autopilot, log, manual-test, prune-logs, purge, refactor, resume, review, review-issue, review-jira,
|
|
187
|
-
routines, save, scan, search, setup, stack, status, sync, test, uninstall, update
|
|
233
|
+
routines, save, scan, search, setup, stack, status, sync, test, testflight-validation, uninstall, update
|
|
188
234
|
```
|
|
189
235
|
|
|
190
236
|
**NOT synced**: `refs/*` - Lazy-load references, Claude Code specific
|
|
@@ -200,8 +246,43 @@ routines, save, scan, search, setup, stack, status, sync, test, uninstall, updat
|
|
|
200
246
|
| `gh` CLI (personal) | `{owner}` gh auth (Keychain) |
|
|
201
247
|
| `gh` CLI (work) | `${USER}_{work-gh-alias}` gh auth (Keychain) |
|
|
202
248
|
| npm publish | `NODE_AUTH_TOKEN` - `GITHUB_TOKEN` in CI, Keychain PAT locally |
|
|
203
|
-
| dev-toolkit publish (Step 3d) | `
|
|
249
|
+
| dev-toolkit publish (Step 3d) | scope-resolved key (`github_<scope>`, else `github`, else `npm`) -> throwaway `--userconfig`, registry from that repo's `publishConfig` |
|
|
204
250
|
|
|
205
251
|
```bash
|
|
206
252
|
gh auth switch --user {owner} # for personal repos
|
|
207
253
|
```
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
## Pre-flight the token scope
|
|
257
|
+
|
|
258
|
+
GitHub reports a token's scopes on any authenticated request, so check before
|
|
259
|
+
uploading instead of reading it out of a 403:
|
|
260
|
+
|
|
261
|
+
```bash
|
|
262
|
+
curl -sI -H "Authorization: token $TOKEN" https://api.github.com/user \
|
|
263
|
+
| grep -i '^x-oauth-scopes:' | grep -q 'write:packages'
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Candidate order for `npm.pkg.github.com`, because storage location and scope are
|
|
267
|
+
not correlated: `github_<scope>` from the mapping, then `gh auth token -u <scope>`
|
|
268
|
+
(gh's own OAuth token often carries `write:packages` when a hand-made PAT does
|
|
269
|
+
not), then the generic `github` key only on a single-identity machine. Take the
|
|
270
|
+
first candidate whose scopes include `write:packages` AND whose login matches the
|
|
271
|
+
package scope. If none qualifies, stop before publishing and report each candidate
|
|
272
|
+
with the login it resolved to and the scope it was missing - that is the
|
|
273
|
+
actionable output, not a 403 body.
|
|
274
|
+
|
|
275
|
+
## Publish 403s: two causes, two fixes
|
|
276
|
+
|
|
277
|
+
Neither message says "wrong token" plainly, and they need opposite responses:
|
|
278
|
+
|
|
279
|
+
- `Unauthorized: As an Enterprise Managed User, you cannot access this content` -
|
|
280
|
+
the resolved token belongs to a corporate EMU account, which cannot publish to a
|
|
281
|
+
personal scope at all. No scope grant fixes this; map the personal account's PAT
|
|
282
|
+
under `github_<scope>`.
|
|
283
|
+
- `The token provided does not match expected scopes` - right account, missing
|
|
284
|
+
permission. Regenerate as a **Classic** PAT with `write:packages`
|
|
285
|
+
(plus `repo` for a private package) and re-onboard through setup.
|
|
286
|
+
|
|
287
|
+
Always report which of the two occurred. "Permission denied" alone sends the user
|
|
288
|
+
to regenerate a token that was never the problem.
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: multi-agent-testflight-validation
|
|
3
|
+
language: en
|
|
4
|
+
description: "Pre-submission validation for a TestFlight / App Store build (iOS, local-only). Three gates: static archive audit, Apple's own `altool --validate-app`, and a Review-Guidelines check. ITMS codes are mapped to the rule each implies. Validates only, never uploads. Use when a build is about to go to TestFlight, or a submission was rejected and you need why."
|
|
5
|
+
user-invocable: true
|
|
6
|
+
argument-hint: "[repo] - empty = pick from prefs; repo name or path; --ipa=<path>; --archive=<path>; --resume"
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# multi-agent-testflight-validation - pre-submission validation
|
|
10
|
+
|
|
11
|
+
Catch, before you upload, what App Store Connect would send back after you do.
|
|
12
|
+
|
|
13
|
+
**Local-only**: no commits, no push, no PR, no channels. **It never uploads** - only
|
|
14
|
+
`--validate-app` is ever invoked, never `--upload-app`.
|
|
15
|
+
|
|
16
|
+
## Why three gates
|
|
17
|
+
|
|
18
|
+
Each sees something the others structurally cannot, so reporting one as "the check"
|
|
19
|
+
is how a build passes locally and gets rejected anyway.
|
|
20
|
+
|
|
21
|
+
| Gate | Runs | Needs | Sees | Blind to |
|
|
22
|
+
|---|---|---|---|---|
|
|
23
|
+
| **1. Static** | `ios_app_store_audit` (18 rules) | `.xcarchive` | privacy manifest, required-reason API, Info.plist, signing, entitlements, embedded SDK, IPv6, debug leak | anything account-dependent |
|
|
24
|
+
| **2. Authoritative** | `ios_testflight_validate` → `altool --validate-app` | `.ipa` + credentials | unregistered bundle ID, profile/app-record mismatch, **version+build already used**, entitlement not provisioned | the Review Guidelines |
|
|
25
|
+
| **3. Guideline** | `app-store-review` skill + repo evidence | repo checkout | ATT, privacy policy, account deletion, IAP, purpose-string wording | anything not in source |
|
|
26
|
+
|
|
27
|
+
Most "we passed validation and still got rejected" cases are Gate 3 findings:
|
|
28
|
+
Apple's validator does not read the Review Guidelines.
|
|
29
|
+
|
|
30
|
+
## Flow
|
|
31
|
+
|
|
32
|
+
**0. Input.** `(empty)` → ask · `my-ios-app`/path → that repo · `--ipa=<path>` →
|
|
33
|
+
Mode B without Gate 1 · `--archive=<path>` → Mode B with all gates · `--resume`.
|
|
34
|
+
State at `~/.claude/logs/multi-agent/<task_id>/agent-state.json`,
|
|
35
|
+
`taskId = TFV-<repo>-<yyyymmddHHMM>`. Register phases with
|
|
36
|
+
`bash ~/.copilot/scripts/phase-tracker.sh` and render with
|
|
37
|
+
`phase-tracker.sh render` at every boundary.
|
|
38
|
+
|
|
39
|
+
**1. Pickers.** Repo (iOS entries in `prefs.projects`; a single match auto-resolves,
|
|
40
|
+
and the breadcrumb says so) → branch → mode. Print
|
|
41
|
+
`Step <i>/<n>: <what this decides>` for each. On `git fetch` failure do **not**
|
|
42
|
+
silently use a cached ref, and **classify the failure before naming a cause**:
|
|
43
|
+
`could not read Password` / `Authentication failed` / `403` is a credential
|
|
44
|
+
problem, not a network one, and a VPN cannot fix it; `Could not resolve host` /
|
|
45
|
+
`Operation timed out` is the network. Show the stderr line verbatim next to your
|
|
46
|
+
classification, then offer the remedy that matches it. Only the network case gets
|
|
47
|
+
the continue-on-a-stale-ref option: for a credential failure, staleness is
|
|
48
|
+
unrelated to what broke.
|
|
49
|
+
|
|
50
|
+
**2. Pre-flight.** `xcrun --find altool` and `xcodebuild -version`; a missing
|
|
51
|
+
prerequisite halts. Resolve credentials and name the active tier in the report:
|
|
52
|
+
tier 1 ASC API key (key id + issuer id from the keychain via
|
|
53
|
+
`prefs.global.keychainMapping`, `.p8` at
|
|
54
|
+
`~/.appstoreconnect/private_keys/AuthKey_<keyId>.p8`), tier 2 Apple ID +
|
|
55
|
+
app-specific password by keychain reference, tier 3 none → **Gate 2 is `SKIPPED`
|
|
56
|
+
and the verdict line says so**. Credentials come from `/multi-agent:setup`; never
|
|
57
|
+
prompt for a secret value in chat. Tier 2 needs no elevated App Store Connect
|
|
58
|
+
role, which matters when API-key creation is not permitted on the account.
|
|
59
|
+
|
|
60
|
+
**3. Obtain the build.**
|
|
61
|
+
- Mode B `.xcarchive` → Gate 1 runs; export with `ios_export_ipa` to reach Gate 2.
|
|
62
|
+
- Mode B `.ipa` only → **Gate 1 `SKIPPED (needs .xcarchive)`**. The static audit
|
|
63
|
+
reads archive structure an `.ipa` does not carry. Do not present a two-gate run
|
|
64
|
+
as a full pass.
|
|
65
|
+
- Mode A → worktree at `{projectRoot}/{worktreeBasePath}/{taskId}` (**never under
|
|
66
|
+
`$HOME`**) → `ios_xcodebuild({action: "archive", configuration: "Release",
|
|
67
|
+
destination: "generic/platform=iOS"})` - the simulator default would produce a
|
|
68
|
+
non-distributable archive - then `ios_export_ipa({method:
|
|
69
|
+
"app-store-connect", team_id, ...})`. Leave `allow_provisioning_updates` off
|
|
70
|
+
unless asked: it lets xcodebuild create or modify profiles in the developer
|
|
71
|
+
account, which a validation run has no business doing.
|
|
72
|
+
|
|
73
|
+
**4. Gate 1.** `ios_app_store_audit({archive_path, rules: "all"})`. `error` blocks,
|
|
74
|
+
`warning` advises. Keep each ITMS code - Gate 2 may return the same one, and that
|
|
75
|
+
agreement tells the user it is real.
|
|
76
|
+
|
|
77
|
+
**5. Gate 2.** `ios_testflight_validate({ipa_path, platform: "ios", <creds>})`.
|
|
78
|
+
Render the verdict as returned: `PASS` / `FAIL` (each issue with ITMS code, mapped
|
|
79
|
+
guideline, hint) / `SKIPPED` (with the reason, **never as a pass**). This is the
|
|
80
|
+
only gate that catches an already-used build number - the most common wasted
|
|
81
|
+
upload - so when it fails on that, name the next free build number.
|
|
82
|
+
|
|
83
|
+
**6. Gate 3.** Load `app-store-review` and check, with an evidence path each:
|
|
84
|
+
purpose strings (present, specific, matching actual use) · `PrivacyInfo.xcprivacy`
|
|
85
|
+
(exists, declares required-reason APIs, matches linked SDKs) · ATT before any
|
|
86
|
+
tracking · in-app account deletion when accounts are created · privacy policy
|
|
87
|
+
reachable · IAP through StoreKit with no external purchase path · Sign in with
|
|
88
|
+
Apple alongside third-party social login. Mark `pass` / `fail` /
|
|
89
|
+
`not-applicable`, and `not-applicable` needs a reason - an unexamined area is not
|
|
90
|
+
a pass.
|
|
91
|
+
|
|
92
|
+
**7. Report.** `~/TestFlightChecks/<repo>-<branch>-<timestamp>/report.md` plus a
|
|
93
|
+
printed summary:
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
Verdict: <N> of 3 gates cleared[, <M> skipped]
|
|
97
|
+
Build: <path> · <bundle id> <version> (<build>)
|
|
98
|
+
Auth: tier <1|2|none> · <method>
|
|
99
|
+
|
|
100
|
+
Gate 1 static audit PASS | FAIL (<n> blocking, <n> advisory) | SKIPPED (<reason>)
|
|
101
|
+
Gate 2 Apple validation PASS | FAIL (<n> issues) | SKIPPED (<reason>)
|
|
102
|
+
Gate 3 guideline review PASS | FAIL (<n> findings) | <n> not-applicable
|
|
103
|
+
|
|
104
|
+
Blocking - fix before uploading
|
|
105
|
+
[ITMS-90683] Info.plist: NSCameraUsageDescription missing
|
|
106
|
+
guideline 5.1.1 Data Collection and Storage
|
|
107
|
+
<hint> · <file:line>
|
|
108
|
+
|
|
109
|
+
Not run
|
|
110
|
+
Gate 1: needs an .xcarchive; only an .ipa was supplied
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
A skipped gate is never folded into the pass count. Every blocking finding carries
|
|
114
|
+
a file path or an ITMS code. No AI or assistant attribution anywhere; real
|
|
115
|
+
newlines, no HTML entities.
|
|
116
|
+
|
|
117
|
+
**8. Offer, do not act.** Print the exact `xcrun altool --upload-app` command for
|
|
118
|
+
when the gates are clear (uploading stays an explicit human act), plus
|
|
119
|
+
`--resume` after fixes and `/multi-agent:fix-bug` for code-level Gate 3 findings.
|
|
120
|
+
Never upload, never bump the build number, never commit.
|