storebound/docs/pitfalls.md
CRT 81313b6fa4 console fill: no silent waits; an unknown page gets a debug dump and a bounded stop
A real `console fill apple-app-privacy` clicked Next onto a console page
the engine did not recognise and logged nothing for 8 hours.

- Step watchdog: after a click, or while the form is expected, no known
  page within --step-timeout seconds (default 30) -> "the page after
  "Next" is not a page storebound knows ... Buttons there: ...", a debug
  dump, and the manual steps. It keeps watching, but 20 min without
  progress closes the window and exits 1.
- A heartbeat line every minute while waiting (also during sign-in); the
  final review wait is bounded (2 h) with a reminder every 10 min.
- Debug dump (cli/console/debug.ts) in .storebound/console-debug/
  <form>-<time>/: page.json (URL without query, headings, dialogs, every
  visible control with role and name), page.html (rebuilt from a clone:
  no scripts, values, hidden inputs or non-whitelisted attributes) and a
  small screenshot. Emails, phone numbers and the header / account area
  are replaced; cookies, storage and tokens are never read.
  --debug-dump writes one at every step for bug reports.
- Guardrail tests: an unknown-page fixture (dump sanitized, bounded exit)
  and a scan of cli/console for while loops without a deadline and
  Playwright waits without a timeout (one waitForLoadState fixed).
- Pitfall 14 (docs/pitfalls.md, store-pitfalls skill); the
  console-autofill skill says how to send a dump.
2026-10-12 07:08:10 +08:00

5.7 KiB

Pitfalls: lessons from real use

A changelog of mistakes found while shipping real apps and games with storebound, newest first. Each entry says what went wrong, why, and what now guards it. The agent-facing short version is skills/store-pitfalls/SKILL.md; keep the two in step.

Rule (CONTRIBUTING.md): every bug found in real use adds an entry here and, where possible, a check or a test that fails without the fix.

# date lesson guard
14 2026-10 console fill apple-app-privacy clicked Next onto a real console page it did not recognise and then waited 8 hours without a single log line. Every wait of the console engine is bounded: a step watchdog (--step-timeout, 30 s) writes a sanitized debug dump to .storebound/console-debug/ and prints the page's buttons and the manual steps; a line a minute while waiting; no progress for 20 min stops the run with exit 1; --debug-dump dumps every step (cli/console/debug.ts, tests/console-flow.test.ts, which also scans the engine for waits without a deadline).
13 2026-10 App Privacy purposes were over-mapped: Play "advertising" became both Third-Party Advertising and Developer's Advertising or Marketing (Device ID, Coarse Location, Product Interaction, Performance Data). applePurpose maps one Play purpose to one Apple purpose (advertising: third-party only); Developer's Advertising only from appPrivacy.types; check compares appPrivacy.types with Info.plist / PrivacyInfo.xcprivacy (tests/app-privacy.test.ts).
12 2026-10 A new Play app has no API: Play Console's "Create app" is the only way, its page-level button carries the same words as the form's final submit, and Free cannot become Paid later. console fill play-app-record: createAppAllowed lets the opener through only on the app list, never in a form or dialog (EN + TR); declarations never ticked; Free / Paid outlined as an owner check (tests/console-fill.test.ts).
11 2026-10 Google Play has no public search API, so there is no Play keyword rank or Play competitor list to read without scraping. aso reads App Store search only (iTunes Search API); aso audit covers Play through the listing text (short description, density); the aso-basics skill says so.
10 2026-10 The iTunes Search API order is close to, not equal to, App Store search (no personalisation, no search ads, no in-app event rows) and it has no subtitle field. aso rank / aso competitors / aso audit label ranks as a trend and show no competitor subtitles; popularity only from Apple Ads, never estimated (cli/lib/aso-intel.ts).
9 2026-10 A retried or repeated write can duplicate on a live store: a POST create retried after a timeout or 5xx, a re-run during the list lag right after a create, two runs at once, a Play edit redone after an unclear commit, a crash in the middle of a screenshot set. Every write is an upsert (cli/lib/upsert.ts: findOrCreate with a fresh re-check and a journal of recent creates, createOnce treating 409 as found, no blind retry of a create); API clients retry only requests that are safe twice; Play edits are all or nothing; asset sets keep the matching prefix; one lock per app and store (cli/lib/lock.ts, --force-unlock). Table: docs/idempotency.md; tests/idempotency.test.ts runs every write twice and asserts zero writes on the second run.
8 2026-10 Capacitor plugins in a monorepo live in apps/native/node_modules, so scan missed them. scan / privacy-manifest resolve workspace packages (cli/lib/scan/project.ts, cli/lib/node-packages.ts).
7 2026-10 Console UIs: the App Store Connect sign-in runs in an idmsa.apple.com iframe; "User Access" is a plain heading, not a labeled group; Chrome drops session cookies without --restore-last-session. console session and fill (cli/console/), tests/console-*.test.ts.
6 2026-10 Screenshot fonts: only part of the glyphs a language needs were available, so Turkish / Polish / Vietnamese characters fell back to another font silently. shots fonts / shots check check every language's characters against the fonts (tests/glyphs.test.ts).
5 2026-10 Account features do not imply email collection; Data safety said "email collected" without evidence. scan marks email only with code evidence, else "ask owner" (cli/lib/scan/declare.ts).
4 2026-10 The App Store keyword limit (100) counts UTF-8 bytes, not characters. check counts bytes (cli/lib/copy.ts).
3 2026-10 App Store app names are unique per storefront: "already being used" although the developer owns no such app. apple.name (App Store name with a suffix the owner picks); app.name stays the brand.
2 2026-10 Dry runs that print no plan ("listing: 20 locales") break "show the dry run to the owner". cli/lib/dry.ts dryPlan(title, rows); tests/pitfalls.test.ts scans cli/** for --dry branches that print only a count (allowlist with TODOs for commands being fixed).
1 2026-10 App Store Connect's /inAppPurchasesV2 list lags right after apple iap creates a product; apple iap-review then skipped it silently. apple iap-review names config products missing from the store's list and exits 1; apple iap and play products re-read the list after creating and warn (cli/lib/store-lag.ts, tests/pitfalls.test.ts).

Adding an entry

  1. A row above (next number, month, one-sentence lesson, the guard with file or test names).
  2. A section in skills/store-pitfalls/SKILL.md: symptom → cause → what to do → which command guards it. Then bun tools/gen-adapters.ts.
  3. Where the code can know it: a check (check, validate, scan, a warning in the command) and a test with recorded store answers that fails without the fix.