appstore-precheck 1.11.0 → 1.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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ All notable changes to this project are documented here. Versioning follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [1.12.0] - 2026-07-02
9
+
10
+ Roadmap #5 (final roadmap item): an **optional, opt-in local dynamic simulator tier** —
11
+ agent-mode, advisory, and off by default. It never changes the verdict and never runs
12
+ in the offline CLI / npx / GitHub-Action path.
13
+
14
+ When the user explicitly asks for a dynamic check and supplies a built app (or a booted
15
+ simulator UDID + bundle id), the host model can run the app on a disposable simulator via
16
+ `xcrun simctl` + Maestro MCP tools and observe real behavior a static scan cannot — launch
17
+ without crashing (2.1), core screen reachable, paywall actually renders with terms (3.1.2),
18
+ permission prompt matches its `Info.plist` purpose string (5.1.1), a demo/login path works
19
+ (2.1), and live UI matches the marketing screenshots (2.3.5). It emits advisory
20
+ `DYNAMIC-PASS:` / `DYNAMIC-FINDING:` lines, exactly like Pierre deep-review's `REVIEW-*`
21
+ lines. It is the free/local alternative to a paid cloud device farm — a pre-submit local
22
+ smoke signal, **not** a TestFlight / crash-reporter / QA replacement.
23
+
24
+ ### Added
25
+ - **`skills/appstore-precheck/references/simulator-dynamic-review.md`** — the 6-check
26
+ agent-mode dynamic checklist (D1–D6) with advisory output format, modeled on the existing
27
+ deep-review reference docs.
28
+ - **`SKILL.md`** — an optional "Phase 6" section (off by default) plus a scoped READ-ONLY
29
+ caveat and an updated "Known limits" note.
30
+ - Methodology + README notes describing the tier.
31
+
32
+ ### Notes
33
+ - Documentation-only: the offline scan path (`scan.sh`/`verdict.sh`/`bin/cli.js`/`action.yml`)
34
+ is byte-identical. READ-ONLY preserved — the tier touches only disposable simulator state,
35
+ never the user's repo. It is permanently local-only (macOS + Xcode + a simulator; it cannot
36
+ run in this project's `ubuntu-latest` CI). A deterministic `simulator-smoke.sh` and authored
37
+ Maestro flows are deliberately deferred (simulator crash-timing is too flaky to ship as an
38
+ unvalidated deterministic check).
39
+
8
40
  ## [1.11.0] - 2026-07-02
9
41
 
10
42
  Roadmap #3: **rejection-outcome feedback loop** — a third, honestly-scoped measurement
package/README.md CHANGED
@@ -468,8 +468,10 @@ CI runs ShellCheck, JSON validation, the version-consistency guard, and the fixt
468
468
 
469
469
  This is a static heuristic tool plus Pierre's semantic deep review. A GREEN result **lowers but does
470
470
  not eliminate** rejection risk; Apple's guidelines change frequently and reviewer decisions are
471
- judgment calls. `REVIEW-FINDING` lines are advisory and do not block the token by themselves. It
472
- performs no runtime crash testing; always do a final manual review before you submit. Not affiliated
471
+ judgment calls. `REVIEW-FINDING` lines are advisory and do not block the token by themselves. The
472
+ default flow performs no runtime crash testing; an optional, opt-in local simulator tier
473
+ (Maestro and `xcrun simctl`) adds a pre-submit smoke signal but is not a TestFlight / crash-reporter
474
+ / QA replacement. Always do a final manual review before you submit. Not affiliated
473
475
  with Apple.
474
476
 
475
477
  ## Star History
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appstore-precheck",
3
- "version": "1.11.0",
3
+ "version": "1.12.0",
4
4
  "description": "Read-only iOS App Store pre-submission check, packaged as a portable Agent Skill with native Claude Code, Cursor, and Codex plugins, plus an npx CLI.",
5
5
  "license": "MIT",
6
6
  "author": "Berkay Turk (https://github.com/berkayturk)",
@@ -4,7 +4,7 @@ description: Read-only pre-submission check for an iOS app before App Store revi
4
4
  license: MIT
5
5
  metadata:
6
6
  author: Berkay Turk
7
- version: 1.11.0
7
+ version: 1.12.0
8
8
  allowed-tools: Bash Read Grep Glob WebFetch
9
9
  ---
10
10
 
@@ -92,7 +92,7 @@ Rules:
92
92
  **English** (Français + user lang, or just Français if they asked in French).
93
93
  - Keep each one-liner short (one sentence). Vary wording each run; stay in Pierre's dry critic voice.
94
94
 
95
- ## Flow (6 phases: 0–5)
95
+ ## Flow (Phases 0–5; plus an optional opt-in Phase 6)
96
96
 
97
97
  ### Phase 0: Live guideline drift check
98
98
 
@@ -314,9 +314,27 @@ narrative; verdict.sh just pins the threshold arithmetic. `REVIEW-FINDING` lines
314
314
  7. Print the final manual checklist (see
315
315
  [`references/methodology.md`](references/methodology.md#pre-submit-manual-checklist)).
316
316
 
317
+ ### Phase 6: local dynamic simulator tier (optional, opt-in — off by default)
318
+
319
+ **This phase does not run by default.** Run it ONLY when the user explicitly asks for a dynamic /
320
+ simulator check AND supplies a built app (a simulator `.app` path, or a booted simulator UDID +
321
+ bundle id). It uses `xcrun simctl` + Maestro MCP tools (`mcp__maestro__*`) to launch the app on a
322
+ disposable simulator and observe real behavior — the free/local alternative to a paid cloud device
323
+ farm.
324
+
325
+ It emits advisory `DYNAMIC-PASS:` / `DYNAMIC-FINDING:` lines and **never changes the
326
+ GREEN/YELLOW/RED verdict** (the verdict stays derived only from Phases 0–2). It is read-only w.r.t.
327
+ the user's project — it touches only disposable simulator state, never the repo. It requires macOS +
328
+ Xcode + a simulator runtime and is permanently local-only (it cannot run in CI). It is a pre-submit
329
+ local smoke signal, not a TestFlight / crash-reporter / QA replacement.
330
+
331
+ Follow [`references/simulator-dynamic-review.md`](references/simulator-dynamic-review.md) for the
332
+ 6-check dynamic checklist and output format.
333
+
317
334
  ## Rules
318
335
 
319
- - **READ-ONLY:** never change code or assets. Only report and write the token.
336
+ - **READ-ONLY:** never change code or assets. Only report and write the token. (The optional Phase 6
337
+ simulator tier touches disposable simulator state only — never the user's project.)
320
338
  - **Speed > exhaustiveness:** `scan.sh` uses parallel grep/jq and finishes in seconds.
321
339
  - **No error swallowing:** if any scan command fails, that line is reported as FAIL and the scan continues.
322
340
  - **Token location:** `.precheck-pass` at the repo root; the guard tests it with an `mmin -60` filter.
@@ -324,7 +342,9 @@ narrative; verdict.sh just pins the threshold arithmetic. `REVIEW-FINDING` lines
324
342
 
325
343
  ## Known limits
326
344
 
327
- - No runtime crash testing; that's TestFlight + a crash reporter. Static analysis only.
345
+ - The default flow is static analysis only. Runtime crash/behavior testing is available as an
346
+ optional, opt-in local simulator tier (Phase 6, `references/simulator-dynamic-review.md`); it is a
347
+ pre-submit local smoke signal, not a TestFlight / crash-reporter replacement.
328
348
  - Several checks are advisory WARNs gated on detected signals (Sign in with Apple 4.8,
329
349
  external-purchase 3.1.1(a), tracking/IDFA without ATT, analytics vs privacy manifest, metadata
330
350
  URLs and placeholder copy). The export-compliance key is flagged when absent, but the actual
@@ -246,6 +246,19 @@ which rules fire. Contribute an outcome via the "App Store outcome" issue templa
246
246
 
247
247
  ---
248
248
 
249
+ ### Optional local dynamic simulator tier
250
+
251
+ Beyond the static scan and the agent-mode deep reviews, an **opt-in** local dynamic tier
252
+ (`references/simulator-dynamic-review.md`, SKILL.md Phase 6) can run the app on a simulator
253
+ (`xcrun simctl` + Maestro MCP) and emit advisory `DYNAMIC-PASS:` / `DYNAMIC-FINDING:` observations —
254
+ launch/crash, paywall render, permission prompt vs purpose string, demo-login path, live UI vs
255
+ marketing screenshots. It is off by default, never changes the verdict, is read-only w.r.t. the
256
+ user's project (touches disposable simulator state only), and is permanently local-only (it cannot
257
+ run in CI). It is a pre-submit local smoke signal, not a TestFlight / crash-reporter / QA
258
+ replacement.
259
+
260
+ ---
261
+
249
262
  ## Pre-submit manual checklist
250
263
 
251
264
  Things the scanner cannot verify; confirm by hand before you submit:
@@ -0,0 +1,88 @@
1
+ # Local dynamic simulator tier (agent-mode, opt-in, non-blocking)
2
+
3
+ The fourth, opt-in tier: a **local dynamic** review that runs the app on a simulator and observes
4
+ real behavior — the class of checks a static scan cannot make (does it launch without crashing, does
5
+ the paywall actually render, does a permission prompt match its purpose string, does a demo login
6
+ work, does the live UI match the marketing screenshots). It is the free/local alternative to a paid
7
+ cloud device farm, built from `xcrun simctl` + Maestro MCP tools (`mcp__maestro__*`) already
8
+ available on a Mac with Xcode.
9
+
10
+ **Identity:** runs ONLY in agent-skill mode, ONLY when the user explicitly asks for it and supplies a
11
+ built app (or a booted simulator UDID + bundle id). It is NOT part of the offline CLI / npx /
12
+ GitHub-Action scan, and it never runs by default. Requires macOS + Xcode + a simulator runtime; it
13
+ cannot run in this project's `ubuntu-latest` CI and is permanently local-only.
14
+
15
+ **This tier never changes the verdict.** GREEN/YELLOW/RED comes only from the static scan counts
16
+ (Phases 0–2). This tier emits advisory `DYNAMIC-PASS:` / `DYNAMIC-FINDING:` lines, like Pierre
17
+ deep-review's `REVIEW-*` lines.
18
+
19
+ **Read-only:** read-only w.r.t. the user's project — the tier installs/launches onto a **disposable
20
+ simulator** only and never modifies the user's repo. Prefer a dedicated/disposable simulator device;
21
+ do not disturb the user's everyday simulator state; leave teardown to the user unless the tier
22
+ created the device itself.
23
+
24
+ **Not a guarantee:** a pre-submit local smoke signal — NOT a replacement for TestFlight, a crash
25
+ reporter, or real-device QA.
26
+
27
+ ## Rules
28
+
29
+ - Advisory only: every check reports `DYNAMIC-PASS:` or `DYNAMIC-FINDING:` — never `FAIL`, never a
30
+ verdict contribution.
31
+ - Evidence-based: cite a screenshot filename + what was observed. If a check cannot be driven (no
32
+ paywall in this app, a UI selector can't be found, no permissions declared), report
33
+ `DYNAMIC-PASS: … — not applicable` or `DYNAMIC-FINDING: … could not verify` — never invent a
34
+ failure.
35
+ - All 6 checks, every run: report each as PASS / FINDING / not-applicable.
36
+ - Boot a disposable simulator, launch the supplied app, and tear down cleanly.
37
+ - Write Pierre's 2–3 sentence explanations in the user's conversation language.
38
+
39
+ ## The 6 checks
40
+
41
+ | # | Guideline | Dynamic question |
42
+ |---|-----------|------------------|
43
+ | D1 | **2.1** | Does the app launch on a fresh simulator and stay foregrounded briefly without crashing / a crash alert? |
44
+ | D2 | **2.1** | Does it reach a real first screen (not stuck on a splash, a blank screen, or an error alert)? |
45
+ | D3 | **3.1.2** | If a paywall/subscription exists, does it render with price + trial/auto-renew/terms visible on-screen (not just present as strings)? |
46
+ | D4 | **5.1.1(ii)/(iii)** | For each permission with an `Info.plist` purpose string, does the OS prompt appear at the right moment and match the declared string? |
47
+ | D5 | **2.1** | For a login-gated app, is there a reachable guest/demo path, or do the declared review demo credentials actually log in? |
48
+ | D6 | **2.3.5** | Do live screenshots of key screens match the submitted marketing screenshots (features shown match the running build)? |
49
+
50
+ ## Per-check procedure
51
+
52
+ ### D1 — Launch without crash
53
+ 1. `mcp__maestro__start_device` (or `xcrun simctl boot`) a disposable simulator; `launch_app` the supplied app/bundle id.
54
+ 2. Observe for a short window; if the app process disappears or a crash alert shows, `DYNAMIC-FINDING`.
55
+ 3. `take_screenshot` at launch as evidence.
56
+
57
+ ### D2 — Core screen reachable
58
+ 1. After launch, inspect the first real screen (`inspect_view_hierarchy` / `take_screenshot`).
59
+ 2. Flag if stuck on a splash, blank, or an error/"something went wrong" state.
60
+
61
+ ### D3 — Paywall renders
62
+ 1. If a paywall exists (per the static scan / app structure), navigate to it (`tap_on` / a flow).
63
+ 2. Confirm price + trial/auto-renew/cancel terms are visibly rendered; screenshot. Not applicable if no paywall.
64
+
65
+ ### D4 — Permission prompt vs purpose string
66
+ 1. For each `NS*UsageDescription` in `Info.plist`, trigger the feature that requests it.
67
+ 2. Confirm the OS prompt appears at the right moment and its text matches the declared purpose string; screenshot.
68
+
69
+ ### D5 — Demo / login path
70
+ 1. For a login-gated app, look for a guest/demo entry, or enter the declared review demo credentials.
71
+ 2. Confirm a reachable path to core features; `DYNAMIC-FINDING` if the only path is a wall with no working demo.
72
+
73
+ ### D6 — Live UI vs marketing screenshots
74
+ 1. Capture live screenshots of key screens.
75
+ 2. Compare to the submitted marketing screenshots; flag features shown in marketing but absent in the running build.
76
+
77
+ ## Output format
78
+
79
+ ```
80
+ DYNAMIC-PASS: <guideline> — <one-line why it looks OK, with screenshot filename>
81
+ ```
82
+ or
83
+ ```
84
+ DYNAMIC-FINDING: <guideline> — <one-line concrete issue, with screenshot filename>
85
+ Pierre: <2–3 sentences: why Apple cares, what you saw, what to fix or verify>
86
+ ```
87
+
88
+ End with a summary table: 6 checks → count of `DYNAMIC-FINDING` vs `DYNAMIC-PASS` (note any not-applicable).