agent rules: first rule "Do it, don't ask" (agents-core and every adapter, README, store-pitfalls lead, first-release, declarations and console skills); the agent runs the real command after the dry run, the owner presses only final public or irreversible buttons and answers compliance facts in one batch; handoff text removed from skills; tests/do-it-dont-ask.test.ts. Pitfall 26
This commit is contained in:
parent
fc524cd2d4
commit
dfc28c15f8
22 changed files with 393 additions and 105 deletions
|
|
@ -29,7 +29,7 @@ other platforms' UI. Play promo video: YouTube URL, public or unlisted, ads off,
|
|||
## Steps
|
||||
1. **Hands-free footage.** Give the game an autoplay / attract mode switch, or the app a scripted demo of its main
|
||||
flow on sample data (URL param, launch argument or intent extra), plus the screenshot switches (language, fixed
|
||||
seed or demo data, no ads). Otherwise record the screen yourself and use `--source folder`.
|
||||
seed or demo data, no ads). Otherwise record the screen (simulator, emulator or browser recording you start) and use `--source folder`.
|
||||
2. **Clips.** `shots.video.record.clips`: per clip `seconds` (1-60) and `path` (web, after `shots.capture.baseUrl`),
|
||||
or `url` / `args` / `extras` (simulator / emulator), `waitFor`, `delayMs`. The source and its settings come from
|
||||
`shots.capture` (or `record.source`). `storebound shots record --dry` shows the plan, then
|
||||
|
|
@ -48,7 +48,9 @@ other platforms' UI. Play promo video: YouTube URL, public or unlisted, ads off,
|
|||
the page with their poster). Watch at least one language end to end.
|
||||
5. **Upload.** App Store: `storebound apple previews --dry`, then `storebound apple previews` (editable version,
|
||||
MD5-idempotent, poster frame from `--poster` / `shots.video.poster`, files checked before anything is sent).
|
||||
Play: upload `preview/youtube/01.mp4` to YouTube yourself, set `play.video`, run `storebound play listing`
|
||||
Play: the video must be on YouTube. Publishing on the owner's channel is public, so ask for it in the start batch
|
||||
(or for an existing video URL); upload it with your browser tool once the owner said yes, set `play.video`, run
|
||||
`storebound play listing`
|
||||
(the listing PUT replaces the whole listing: without `play.video` a video set in Play Console is cleared).
|
||||
|
||||
## From an AI tool (MCP)
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@ or `bun <toolchain>/cli/index.ts`; agents can also use the `storebound mcp` tool
|
|||
Config: `storebound.config.ts`; credentials: `ASC_KEY_ID`, `ASC_ISSUER_ID`, `ASC_P8` (env or
|
||||
`.storebound/credentials.json`, gitignored). All commands are idempotent and have `--dry`. Run `storebound check` first.
|
||||
|
||||
**Ask the owner before submitting for review, releasing, or canceling a submission.** The final "Submit for Review"
|
||||
of a first version is the owner's click. Shared agent rules: `docs/agents-core.md` of the toolchain.
|
||||
**Do it, don't ask** (first rule in AGENTS.md / `docs/agents-core.md` of the toolchain): you run every step below
|
||||
yourself, API steps with storebound and UI steps in App Store Connect with your browser tool, and verify each. The
|
||||
owner only presses Submit for Review, Release, App Privacy Publish, cancels a submission or accepts agreements, and
|
||||
answers the compliance facts no file proves, all in one batch at the start.
|
||||
|
||||
## Steps (API = storebound, UI = App Store Connect / Xcode by hand)
|
||||
## Steps (API = storebound, UI = App Store Connect, driven by you with your browser tool; Local = this machine)
|
||||
|
||||
1. **UI · API key.** App Store Connect > Users and Access > Integrations > App Store Connect API > Team Keys > +
|
||||
(Admin or App Manager). Download `AuthKey_<KEYID>.p8` once, keep it in `~/.appstoreconnect/private_keys/`, note the
|
||||
|
|
@ -49,21 +51,23 @@ of a first version is the owner's click. Shared agent rules: `docs/agents-core.m
|
|||
description / keywords / promo / URLs). Run it with `--dry` first and show the owner the plan: the version decision
|
||||
(keep, update the editable version's string, create, or refuse with the reason), the build, and per locale create /
|
||||
update with old -> new per field. Locales still marked `status=draft` / `status=translate` are skipped until
|
||||
`listing reviewed` (`--include-drafts` only when the owner says so). The real run asks in a terminal and applies
|
||||
exactly that plan. Then `storebound apple release --phased on`: manual release + phased
|
||||
`listing reviewed` (`--include-drafts` only when the owner says so). Then run it yourself with `--yes`: it
|
||||
applies exactly that plan. Then `storebound apple release --phased on`: manual release + phased
|
||||
release is the default for every version (`release-management`).
|
||||
8. **API · Screenshots.** `store-screenshots` skill, then
|
||||
`storebound apple screenshots > .storebound/asc-shots.log 2>&1 &` (6.9" + 6.5" per locale, MD5-idempotent).
|
||||
9. **API · App info.** `storebound apple appinfo` (`--dry` first: old -> new per field): categories, age rating declaration, content rights, Free price,
|
||||
all territories. The **first** availability record of a new app may be refused by the public API (an error on
|
||||
POST /v2/appAvailabilities); then set it once in App Store Connect > Pricing and Availability and re-run (later runs only read it).
|
||||
POST /v2/appAvailabilities); then set it once in App Store Connect > Pricing and Availability with your browser
|
||||
tool and re-run (later runs only read it).
|
||||
10. **API · Review details.** `storebound apple review-details` (contact from `.storebound/credentials.json`
|
||||
`reviewContact`, or `--contact-from <Apple ID of another app of the team>`; notes from the config). Apps behind a
|
||||
sign-in: the demo account from `.storebound/` (`review-access` skill). Apps with accounts: in-app deletion
|
||||
(`account-deletion` skill).
|
||||
11. **API + UI · In-app purchases and subscriptions.** `store-iap-setup` and `store-subscriptions` skills. First
|
||||
IAPs and subscriptions go to review **with** this version.
|
||||
12. **UI · App Privacy.** `store-declarations` skill (nutrition labels), then **Publish**.
|
||||
12. **UI · App Privacy.** `store-declarations` skill (nutrition labels; you fill and save them), then the owner
|
||||
presses **Publish**.
|
||||
13. **Preflight.** `storebound validate --apple` until it shows no blocker (`store-preflight`).
|
||||
14. **UI · Submit.** Version page > Add for Review (with the IAPs in the same draft submission) > Submit for Review
|
||||
(owner). Release type MANUAL means the owner presses "Release" after approval.
|
||||
|
|
|
|||
|
|
@ -72,7 +72,8 @@ true; never use competitor or other apps' or games' names, "best / #1", or unrel
|
|||
owner's step.
|
||||
- A subtitle change ships with a version: change one thing, then compare with `analytics compare`.
|
||||
- Google Play store listing experiments (short / full description, icon, feature graphic, screenshots) have no API:
|
||||
storebound prepares the text and renders; the owner sets the experiment up in Play Console.
|
||||
storebound prepares the text and renders, you set the experiment up in Play Console with your browser tool, and
|
||||
the owner presses the button that starts it.
|
||||
|
||||
## Where the numbers come from (say it to the owner)
|
||||
| number | source | is | is not |
|
||||
|
|
|
|||
|
|
@ -7,6 +7,10 @@ description: Fill App Store Connect and Google Play Console forms that have no A
|
|||
|
||||
CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolchain>/cli/index.ts`).
|
||||
|
||||
**Do it, don't ask** (first rule in AGENTS.md / `docs/agents-core.md`): you open the console, navigate, fill the form,
|
||||
save drafts and verify; the owner only signs in once and presses the final button. Ask the owner's `ask-owner`
|
||||
answers in one batch before you start, never one at a time on the page.
|
||||
|
||||
**Read this to the owner first.** Console pages change without notice. You (the agent) fill the form from storebound's
|
||||
answer sheet and the owner reviews every field and presses the final button. Nobody types a password or touches a
|
||||
sign-in page except the owner; nothing that submits, publishes, creates, accepts an agreement or grants a permission
|
||||
|
|
@ -27,7 +31,8 @@ the UI shows. This is the primary mode.
|
|||
- `buttons.neverPress` (Publish, Submit, Create, Create app, Send, Release, "Definitions and Examples", "?", the
|
||||
final Save of a form ...), `buttons.final` and `buttons.allowed` (navigation and draft saves);
|
||||
- `uiFacts` (verified facts per form, see below), `driving` and `verify` (the command and what to capture).
|
||||
2. Show the owner the `ask-owner` answers and ask (AGENTS.md rule 5). Never guess them; leave them empty if the owner
|
||||
2. Collect the `ask-owner` answers of every form you will fill in ONE question to the owner before you start (AGENTS.md
|
||||
rule 5) and write them into the config, so the plan has them. Never guess them; leave them empty if the owner
|
||||
wants to answer in the page.
|
||||
3. Open `start.url` in your browser tool. If a sign-in page shows, the owner signs in; you wait.
|
||||
4. Follow `steps`. Read the page (text or accessibility tree) before each action, click by visible text, set each
|
||||
|
|
@ -68,15 +73,15 @@ the UI shows. This is the primary mode.
|
|||
left. Text inputs set by `form_input` are fine. After Create app the app lives at
|
||||
`/console/u/0/developers/<developerId>/app/<appId>/app-dashboard`: put the id in `play.appId`.
|
||||
- **After Play Create app, an owner step:** a service account's app-level permissions do NOT cover apps created
|
||||
later. The owner opens Users and permissions > the service account > Add app > the new app > Admin (or the minimal
|
||||
set the plan lists) > Apply > Save changes, then `storebound apps check --store play`. Never do it yourself (a
|
||||
permission grant; auto mode blocks it too).
|
||||
later. Granting them is the owner's (a permission grant; auto mode blocks it too): give the exact path together
|
||||
with the Create app button, Users and permissions > the service account > Add app > the new app > Admin (or the
|
||||
minimal set the plan lists) > Apply > Save changes; then run `storebound apps check --store play` yourself.
|
||||
|
||||
## Optional: the scripted fast path (`storebound console fill`)
|
||||
|
||||
`console fill` drives a visible browser by itself with the same answers and click rules. It is fast when the page
|
||||
matches its model; when it stalls on a changed page, switch to the agent-first mode above instead of waiting for a
|
||||
fix. It is not available over MCP (the owner runs it in a terminal or the desktop app).
|
||||
fix. It is not available over MCP: run it from your shell (or the owner uses the desktop app).
|
||||
|
||||
## Forms
|
||||
|
||||
|
|
@ -93,7 +98,7 @@ fix. It is not available over MCP (the owner runs it in a terminal or the deskto
|
|||
|
||||
1. `storebound console fill` lists the forms. `storebound console fill <form> --dry` prints every answer with its
|
||||
source; `[check]` lines are not proven by the config. Show them to the owner.
|
||||
2. For each `[check]` line, ask the owner (AGENTS.md rule 5: never guess a compliance answer). If they want it filled
|
||||
2. Ask the owner about every `[check]` line in one batch before the run (AGENTS.md rule 5: never guess a compliance answer). If they want it filled
|
||||
next time, add it to the config, for example:
|
||||
```ts
|
||||
console: {
|
||||
|
|
@ -103,8 +108,8 @@ fix. It is not available over MCP (the owner runs it in a terminal or the deskto
|
|||
},
|
||||
```
|
||||
Age rating answers live in `apple.info.ageRating` (also `socialMedia`, `socialMediaAgeRestricted`).
|
||||
3. The owner runs `storebound console fill <form>` in a terminal (or presses the button in the desktop app). The
|
||||
first log line says which browser it uses:
|
||||
3. Run `storebound console fill <form>` yourself from a shell (the desktop app has a button for it too). The first
|
||||
log line says which browser it uses:
|
||||
- **profile** (the default): storebound's own profile (`~/.storebound/console-profile/<store>`, or `--profile <dir>`
|
||||
/ `STOREBOUND_CONSOLE_PROFILE`; one per store, not per account: every studio shares the one login). Nothing is
|
||||
read or copied from the owner's own Chrome. storebound starts Chrome itself as a normal window (its own
|
||||
|
|
@ -158,8 +163,9 @@ fix. It is not available over MCP (the owner runs it in a terminal or the deskto
|
|||
Save, Submit, Publish, Create, Send, Next or the Turkish equivalents; only a LINK named exactly Start / Manage /
|
||||
Başla / Yönet is let through. If a step is not found in time, or two apps match (they are listed: set
|
||||
`apple.appId` / `play.packageName`), storebound says which step failed, prints what to click, and keeps watching:
|
||||
a sign-in that finishes restarts navigation at step 1; when the owner moves on by hand (the + button, the New App
|
||||
item, the app in the list appear) it continues from that step; when the owner opens the form it fills it. Watching
|
||||
a sign-in that finishes restarts navigation at step 1; when the page moves on (you click the step with your
|
||||
browser tool: the + button, the New App item, the app in the list appear) it continues from that step; when the
|
||||
form is open it fills it. Watching
|
||||
ends when the window is closed. When the form appears storebound fills the certain answers, outlines every
|
||||
unproven or unfillable field with a "storebound: check this" label, and lists them in the terminal.
|
||||
5. **One login, many developer accounts or teams.** storebound never asks for a second sign-in; it finds the
|
||||
|
|
@ -204,7 +210,8 @@ fix. It is not available over MCP (the owner runs it in a terminal or the deskto
|
|||
step: attach that folder to a bug report after looking at screen.jpg (labels only; no values, cookies or tokens;
|
||||
emails, phone numbers and the account area are replaced).
|
||||
9. If a field cannot be found or matches twice (for more than a moment: a page that is still loading does not count), the console UI changed: storebound stops filling and prints the
|
||||
step-by-step list ("label: answer") for the owner to copy. That is the expected safe behavior, not an error.
|
||||
step-by-step list ("label: answer"). That is the expected safe behavior, not an error: finish that part yourself
|
||||
with your browser tool (agent-first mode above), not by handing the list to the owner.
|
||||
|
||||
## Play Create app (`play-app-record`)
|
||||
|
||||
|
|
@ -225,7 +232,8 @@ fix. It is not available over MCP (the owner runs it in a terminal or the deskto
|
|||
"Check availability" ("Package name available"). It is fixed for good once the app is created.
|
||||
- App or game and Free or paid are `<material-radio>`s: storebound clicks the inner `[role=radio]` (the native input
|
||||
does not update the form's model). With `play.developerId` the form opens by its own URL (`.../create-new-app`).
|
||||
- After Create app: the owner adds the new app to the service account (see "Verified UI facts" above).
|
||||
- After Create app: the owner grants the service account access to the new app (a permission grant; see "Verified UI
|
||||
facts" above), then you run `storebound apps check --store play`.
|
||||
|
||||
## What storebound clicks, and what stays with the owner
|
||||
|
||||
|
|
@ -242,8 +250,8 @@ content", "Create and set up your app"):
|
|||
| Content rating (Play) | Start; **Save draft** then Next on each page (a draft: IARC gets nothing before Submit; the owner agreed) | **Submit** on the Summary: sends the questionnaire to IARC |
|
||||
| Target audience (Play) | Start / Manage, Next between the pages | **Save** on the last page: stores the declaration, which Google then reviews |
|
||||
|
||||
Mid-way storebound stops only for an uncertain answer (see 6). It never asks the owner to click a navigation button
|
||||
unless the console page changed so that storebound cannot find it (then it says so).
|
||||
Mid-way storebound stops only for an uncertain answer (see 6). A navigation button is never the owner's: when the
|
||||
console page changed so that storebound cannot find it, it says so and you click it with your browser tool.
|
||||
|
||||
## The owner decides
|
||||
|
||||
|
|
|
|||
|
|
@ -10,10 +10,12 @@ or `bun <toolchain>/cli/index.ts`; agents can also use the `storebound mcp` tool
|
|||
It reads `storebound.config.ts` in the project (create with `storebound init`) and credentials from env or
|
||||
`.storebound/credentials.json` (gitignored). Every write command has `--dry`. Run `storebound check` first.
|
||||
|
||||
**Ask the owner before anything public or irreversible**: production releases, "Send for review", publishing,
|
||||
deleting products. Sending a first release for review is the owner's action in the Console, not yours.
|
||||
**Do it, don't ask** (first rule in AGENTS.md / `docs/agents-core.md`): you run every step below yourself, API steps
|
||||
with storebound and UI steps in Play Console with your browser tool, and verify each. The owner only presses the
|
||||
public or irreversible buttons (Send changes for review, production release or rollout, agreements, deleting
|
||||
products) and answers the compliance facts no file proves, all in one batch at the start.
|
||||
|
||||
## Steps (API = storebound does it, UI = Play Console by hand)
|
||||
## Steps (API = storebound, UI = Play Console, driven by you with your browser tool)
|
||||
|
||||
1. **UI · Create the app.** `storebound console plan play-app-record` (then drive the form with your browser tool,
|
||||
or the scripted `storebound console fill play-app-record`). The form is
|
||||
|
|
@ -25,10 +27,11 @@ deleting products. Sending a first release for review is the owner's action in t
|
|||
`/console/u/0/developers/<developerId>/app/<appId>/app-dashboard`: put that app id in `play.appId` (the App
|
||||
content forms deep-link from it).
|
||||
**Owner step after every Create app:** a service account's app-level permissions do NOT cover apps created later.
|
||||
The owner opens Users and permissions > the service account > Add app > the new app > Admin (or at least: view app
|
||||
information, manage store presence, release to testing tracks, manage testing tracks, manage production releases,
|
||||
manage policy declarations, manage orders and subscriptions) > Apply > Save changes. Never do this yourself: it is
|
||||
a permission grant (agents in auto mode are blocked from it too). Then `storebound apps check --store play`.
|
||||
Granting them is the owner's (a permission grant; agents in auto mode are blocked from it too): give the exact
|
||||
path in the same message as the Create app button, Users and permissions > the service account > Add app > the new
|
||||
app > Admin (or at least: view app information, manage store presence, release to testing tracks, manage testing
|
||||
tracks, manage production releases, manage policy declarations, manage orders and subscriptions) > Apply > Save
|
||||
changes. Then run `storebound apps check --store play` yourself.
|
||||
2. **UI · API access.** Google Cloud project (any) > enable "Google Play Android Developer API" > create a service
|
||||
account > JSON key (keep it outside the repo). Play Console > Users and permissions > Invite new users > the
|
||||
service account email > app permissions: view app information, manage store presence, release to testing tracks,
|
||||
|
|
@ -52,7 +55,7 @@ deleting products. Sending a first release for review is the owner's action in t
|
|||
6. **API · Listing text.** Fill `store/listing.md` (one section per language), then `storebound play listing`.
|
||||
It also sets contact email + website (website = the domain serving app-ads.txt). Run `--dry` first and show the
|
||||
owner the plan (details and per language old -> new per field; draft languages skipped until `listing reviewed`,
|
||||
`--include-drafts` only on the owner's word); the real run asks in a terminal and PUTs only what changes.
|
||||
`--include-drafts` only on the owner's word); then run it yourself with `--yes`: it PUTs only what changes.
|
||||
7. **API · Graphics.** Render (`store-screenshots` skill), `storebound shots jpeg`, then
|
||||
`storebound play images > .storebound/play-images.log 2>&1 &` and follow the log (it is slow: one edit per language).
|
||||
Required: the 512 x 512 icon, the 1024 x 500 feature graphic and at least 2 phone screenshots (Play Console Help
|
||||
|
|
@ -68,7 +71,8 @@ deleting products. Sending a first release for review is the owner's action in t
|
|||
with the demo account (`review-access`); with accounts: the delete-account URL (`account-deletion`); subscriptions:
|
||||
`storebound play subscriptions` (`store-subscriptions`).
|
||||
11. **UI · Store settings.** Category + tags, contact details.
|
||||
12. **API + UI · Production.** `storebound play release --version-code N --production draft`, then in the Console:
|
||||
12. **API + UI · Production.** `storebound play release --version-code N --production draft`, then in the Console
|
||||
(you, with your browser tool):
|
||||
Production > Countries/regions > Add countries > select all > Save; Production > the draft release > Edit >
|
||||
Next > Save; Publishing overview > **Send changes for review** (owner).
|
||||
13. **Verify.** `storebound validate --play` (no blockers), `storebound play status` (tracks, listings, products), Console dashboard has no open tasks,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@ description: Repo-local workflows for a mobile app or game - named multi-step fl
|
|||
# Release flows
|
||||
|
||||
CLI: `storebound flow list | validate | run <name> [NAME=value ...] [--dry | --apply] [--from <step> | --resume]`.
|
||||
MCP: `flow_list`, `flow_run` (always the safe mode: writes as dry runs; `--apply` is a terminal command the owner runs).
|
||||
MCP: `flow_list`, `flow_run` (always the safe mode: writes as dry runs; `--apply` is a CLI command: run it from your
|
||||
shell after the dry run).
|
||||
|
||||
## Where flows live
|
||||
- `store/workflows/<name>.yml` (one flow per file, named after the file; `.yaml`, `.json` and `.ts` work too), or
|
||||
|
|
@ -45,11 +46,11 @@ once (the second build step prints "prebuild skipped (already ran in this flow r
|
|||
run for real; **every write step runs with `--dry`**; wait steps check once; shell steps are skipped. Nothing
|
||||
changes. Show this output to the owner.
|
||||
- `--dry`: the plan only, nothing runs.
|
||||
- `--apply`: writes and shell steps run for real, **only after the owner agreed in chat**; each write command still
|
||||
asks its own confirmation in the terminal. Never add `--yes` to a step (flow validate refuses it).
|
||||
- `--apply --yes`: the owner's approval of every write step of this run (they get `--yes`; reads, waits and owner
|
||||
steps do not). Only when the owner said so in chat for this run, e.g. a background run with a log where no terminal
|
||||
can answer. Without `--yes` and without a terminal, a confirming command declines: the flow stops there with
|
||||
- `--apply`: writes and shell steps run for real; each write command still asks its own confirmation in the
|
||||
terminal. Never add `--yes` to a step (flow validate refuses it).
|
||||
- `--apply --yes`: how you run it after showing the dry run (do it, don't ask: AGENTS.md first rule): every write
|
||||
step gets `--yes`; reads, waits and owner steps do not, so nothing owner-only runs. When the dry run shows a live price change
|
||||
(`play products`, `apple subscriptions` on an existing product), get the owner's yes for it first. Without `--yes` and without a terminal, a confirming command declines: the flow stops there with
|
||||
"step N declined: not a terminal and no --yes ...", never "ok" (status `declined` in `--json` and the state file).
|
||||
- Owner steps never run in any mode: submit, release, phased release, rollout, sending review replies, price
|
||||
imports, inviting testers, Beta App Review, starting experiments, offer codes (AGENTS.md rule 1). They print as
|
||||
|
|
|
|||
|
|
@ -71,4 +71,4 @@ Before pushing local texts over a console edit, pull the live ones and read the
|
|||
shared by several codes is only changed when the store has the same text for all of them.
|
||||
- `storebound catalog pull [--write]`: IAP and subscription titles / descriptions (Play: benefits) against the config.
|
||||
`storebound.config.ts` is never rewritten: `--write` saves `.storebound/pull/catalog.json` as a proposal; merge the
|
||||
listings by hand or with your agent, then `storebound check`.
|
||||
listings into the config yourself (the agent), then `storebound check`.
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ keyword repetition, other apps), interstitials at launch, payments outside Play
|
|||
a rejection, run it too: the same cause often hides elsewhere. A finding the owner decided is fine goes
|
||||
into `scan.ignore` with the reason (never silence one yourself).
|
||||
|
||||
Checked at review, not by scan (look at these by hand): crashes and hangs on the reviewer's device (2.1; `store-health`),
|
||||
Checked at review, not by scan (check these yourself in the app and the listing): crashes and hangs on the reviewer's device (2.1; `store-health`),
|
||||
links that are dead at review time (`storebound validate` checks the configured URLs), screenshots and description
|
||||
that do not match the app (2.3, `store-screenshots`), poor or unfinished UI (4.0), "too simple" and spam / template
|
||||
apps (4.2, 4.3; `portfolio-originality`), IAPs that fail in the sandbox (2.1(b), `store-iap-setup`), privacy policy
|
||||
|
|
|
|||
|
|
@ -5,6 +5,11 @@ description: Answer the store compliance forms for a mobile app or game - Google
|
|||
|
||||
# Store declarations
|
||||
|
||||
**Do it, don't ask** (first rule in AGENTS.md): you fill these forms yourself (API, or the console with your browser
|
||||
tool from `storebound console plan`). Ask the owner only the answers no code or config proves, all in one batch at
|
||||
the start, and save them in the config; the owner presses only App Privacy Publish and the final Submit / Save of a
|
||||
console questionnaire.
|
||||
|
||||
`storebound scan` proposes the Data safety and App Privacy answers from the detected SDKs and code (each item "detected (file:line)" or "ask owner") as a diff against `dataSafety` / `appPrivacy`; `--write` adds only the detected ones after the owner agrees.
|
||||
|
||||
Templates: `store/declarations.md` (Play App content + IARC answers), `store/app-privacy.md` (Apple labels), both
|
||||
|
|
@ -21,12 +26,14 @@ CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolc
|
|||
Play cannot read the form back: storebound keeps the hash of the last upload in `.storebound/data-safety.sha256`
|
||||
and skips an unchanged CSV. After a hand edit in Play Console, `--force` sends the config's answers again.
|
||||
Then check the summary in Play Console > Policy and programs > App content > Data safety.
|
||||
3. **Play App content (UI).** Policy and programs > App content, each card with `store/declarations.md`:
|
||||
3. **Play App content (UI, you drive it).** Policy and programs > App content, each card with `store/declarations.md`
|
||||
(`storebound console plan play-content-rating` / `play-target-audience` for the forms it knows):
|
||||
privacy policy, app access, ads, content rating (IARC questionnaire), target audience and content, news, COVID-19,
|
||||
data safety, government apps, financial features, health, advertising ID.
|
||||
4. **Apple age rating (API).** `storebound apple appinfo` (all NONE except your overrides, e.g. `advertising: true`).
|
||||
5. **Apple App Privacy (UI only).** App Store Connect > the app > App Privacy > Get Started / Edit, from
|
||||
`store/app-privacy.md`; per data type: purposes > linked to identity > used for tracking. Then **Publish**.
|
||||
5. **Apple App Privacy (UI only, you drive it: `storebound console plan apple-app-privacy`).** App Store Connect >
|
||||
the app > App Privacy > Get Started / Edit, from `store/app-privacy.md`; per data type: purposes > linked to
|
||||
identity > used for tracking, Save. Then the owner presses **Publish**.
|
||||
- Purposes follow Apple's definitions (developer.apple.com/app-store/app-privacy-details/), one per Play purpose:
|
||||
Play `advertising` (ads from an ad SDK) is **Third-Party Advertising only**, never also Developer's Advertising
|
||||
or Marketing (that one is first-party ads or marketing to your own users: the owner's answer); `analytics` is
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
---
|
||||
name: store-pitfalls
|
||||
description: Known pitfalls with App Store Connect, Google Play and storebound itself, learned from real releases, and what to do about each - store lists that lag right after a create, dry runs that print a count instead of a plan, App Store names taken on a storefront, keyword limits in bytes, Data safety answers without code evidence, missing font glyphs in screenshots, console sign-in and sessions, Capacitor monorepo plugins, duplicates from retries, re-runs and parallel runs, App Store search ranks that are only a trend, Play without a search API, Play's Create app form (no API, opener and submit share a name, Free is final), App Privacy purposes over-mapped (Play advertising is Third-Party Advertising only), an unknown console page, a signed-in console read as a sign-in page (Google account widget frames), console forms driven agent-first, stale Capacitor web assets, a declined flow step logged ok. Read it before any store task, and when a store command does something you did not expect.
|
||||
description: Known pitfalls with App Store Connect, Google Play and storebound itself, learned from real releases, and what to do about each - first: do the work, don't ask the owner for every step; store lists that lag right after a create, dry runs that print a count instead of a plan, App Store names taken on a storefront, keyword limits in bytes, Data safety answers without code evidence, missing font glyphs in screenshots, console sign-in and sessions, Capacitor monorepo plugins, duplicates from retries and re-runs, search ranks that are only a trend, no Play search API, Play's Create app form (no API, opener and submit share a name, Free is final), App Privacy purposes over-mapped (Play advertising is Third-Party Advertising only), an unknown console page, a signed-in console read as a sign-in page, console forms driven agent-first, stale Capacitor web assets, a declined flow step logged ok. Read it before any store task, and when a store command does something you did not expect.
|
||||
---
|
||||
|
||||
# Store pitfalls
|
||||
|
|
@ -8,6 +8,14 @@ description: Known pitfalls with App Store Connect, Google Play and storebound i
|
|||
Each entry: **symptom** → cause → what to do → what guards it now. The full changelog of lessons with dates is
|
||||
`docs/pitfalls.md` in the storebound repository. When you hit a new one, tell the owner and add it there (and here).
|
||||
|
||||
## First: do it, don't ask (the costliest pitfall)
|
||||
You and storebound do everything: API calls, uploads, builds, CSV / template exports, every console navigation
|
||||
(open, Get Started, Edit, Next, Continue, Save draft), console forms, verification. Never hand the owner "run this" or
|
||||
"click X". The owner presses only the final public or irreversible buttons (Submit for review, release or a
|
||||
production rollout, App Privacy Publish, legal agreements; deleting store data, live prices, review replies,
|
||||
testers) and answers, in ONE batch at the start, only the facts no file proves (compliance answers that `check` /
|
||||
`validate` list). Loop: plan, drive, verify, continue. Full rule: `docs/agents-core.md` (AGENTS.md); lesson 26.
|
||||
|
||||
## 1. A product you just created is "not there"
|
||||
- **Symptom:** `apple iap-review` uploads nothing for a product `apple iap` created a minute ago; a list looks short.
|
||||
- **Cause:** App Store Connect's `/inAppPurchasesV2` list (and Play's product list) can lag for a short while after a
|
||||
|
|
@ -135,7 +143,7 @@ Each entry: **symptom** → cause → what to do → what guards it now. The ful
|
|||
- **Cause:** the console showed a page storebound does not recognise (a changed layout, a new question): no field it
|
||||
can fill and no button it may click.
|
||||
- **Do:** read the warning: it names the page ("the page after "Next""), its buttons, and where the debug dump is.
|
||||
Do that part by hand (the manual steps follow), or stop. To report it, re-run with `--debug-dump` and attach the
|
||||
Drive that part yourself with your browser tool from `storebound console plan <form>` (agent-first), then go on. To report it, re-run with `--debug-dump` and attach the
|
||||
folder `.storebound/console-debug/<form>-<time>/` after the owner looked at `screen.jpg` (the screenshot shows what
|
||||
the window showed). `page.json` / `page.html` hold labels and structure only: no values, cookies or tokens; emails,
|
||||
phone numbers and the account area are replaced.
|
||||
|
|
@ -291,8 +299,8 @@ that fails without the fix (see CONTRIBUTING.md).
|
|||
`apple testflight wait` for a build that was never uploaded.
|
||||
- **Cause:** a declined confirmation (`confirm()` in `cli/lib/ctx.ts`) returned from the command with exit 0, and
|
||||
`flow run --yes` was not passed on to the steps, so a run without a terminal could never confirm.
|
||||
- **Do:** read a step's output, not only its status. For a run without a terminal the owner can approve the writes
|
||||
with `flow run <name> --apply --yes` (only on their word, per run); otherwise run the flow in a terminal.
|
||||
- **Do:** read a step's output, not only its status. After showing the dry run, run the writes yourself with
|
||||
`flow run <name> --apply --yes` (owner steps never run in a flow, they print as "YOUR CLICK").
|
||||
- **Guard:** every declined or unanswerable confirmation prints `declined: <reason>` and exits 3 (`DECLINED_EXIT`);
|
||||
`flow run` stops with "step N declined: <reason>" (status `declined`, never `ok`) and adds `--yes` to write steps
|
||||
only with `--apply --yes` (`planStep` in `cli/lib/flow.ts`, `declinedReason` in `cli/flow.ts`).
|
||||
|
|
@ -315,3 +323,20 @@ that fails without the fix (see CONTRIBUTING.md).
|
|||
`sendParts` in `cli/apple/upload.ts`, `cli/lib/progress.ts` (injectable heartbeat), `waitForBuild` in
|
||||
`cli/apple/testflight.ts`, a 2-minute limit per App Store Connect call (`ASC_REQUEST_TIMEOUT_MS`);
|
||||
`tests/tools-path.test.ts`, `tests/build-sign.test.ts`, `tests/upload-progress.test.ts`.
|
||||
|
||||
## 26. Asking the owner for every step
|
||||
- **Symptom:** an agent using storebound spent hours handing the owner one click, one command or one answer at a
|
||||
time: "open App content", "press Next", "download the CSV template", "now run the upload", "what is your
|
||||
answer for X?" in the middle of a run.
|
||||
- **Cause:** skills and rules said "let the owner do it" and "by hand" for navigation, draft saves, exports and
|
||||
uploads, and compliance questions were asked when the run reached them, not at the start.
|
||||
- **Do:** follow the first rule (top of this file, `docs/agents-core.md`): do every API call, upload, build, export,
|
||||
console navigation and form yourself, verify by reading back, go on. Collect every fact no file proves in one batch
|
||||
at the start (`storebound check` / `validate` list them) and save the answers in the config. Stop only for the
|
||||
owner steps (Submit for review, release / production rollout, App Privacy Publish, legal agreements, deleting store
|
||||
data, live prices, review replies, testers), prepared with the dry run shown. Make `check` / `--dry` catch store
|
||||
refusals so they never surface as a 400 mid-run.
|
||||
- **Guard:** the rule is the first section of `docs/agents-core.md` and so of every generated adapter (AGENTS.md,
|
||||
GEMINI.md, Copilot and Cursor rules), of README and of this skill; `tests/do-it-dont-ask.test.ts` checks that and
|
||||
fails when a skill or the rules hand navigation, draft saves, exports, uploads or form filling to the owner
|
||||
(navigation "by hand", uploads or exports left to the owner, asking the owner to click through a form).
|
||||
|
|
|
|||
|
|
@ -92,8 +92,8 @@ Each line: number, level (`BLOCKER`, `warn`, `ok`), store, message, and a `fix:`
|
|||
Vitals need the Play Developer Reporting API enabled for the service account; without it `validate` only notes
|
||||
"vitals not readable". `--no-health` skips these checks.
|
||||
|
||||
## What validate cannot see (UI-only, check by hand)
|
||||
## What validate cannot see (UI-only: check them yourself in the console with your browser tool)
|
||||
App Privacy labels published, Play App content declarations (ads, target audience, content rating, advertising ID,
|
||||
App access with the demo account), in-app account deletion working, first subscriptions added to the version,
|
||||
agreements / tax / banking, countries for production on Play. (TestFlight groups and testers: `storebound apple
|
||||
testflight status`.) Tell the owner which are still open.
|
||||
testflight status`.) Fix what you can; tell the owner only what is an owner step (agreements, tax, banking).
|
||||
|
|
|
|||
|
|
@ -138,8 +138,8 @@ images there), so only do that after a test has a winner. What the stores offer,
|
|||
- **Google Play store listing experiments** (Play Console > Grow users > Store listing experiments): up to 2 variants
|
||||
against the current listing; one default-graphics experiment or up to 5 localized experiments at a time; icon,
|
||||
feature graphic, screenshots (+ descriptions for localized ones); stops automatically after 6 months. Console only:
|
||||
the Play Developer API has no experiments endpoint, so storebound renders and checks the variant images and you
|
||||
upload them in the experiment form yourself.
|
||||
the Play Developer API has no experiments endpoint, so storebound renders and checks the variant images and the
|
||||
agent uploads them in the experiment form with its browser tool; starting the experiment is the owner's button.
|
||||
https://support.google.com/googleplay/android-developer/answer/6227309
|
||||
- **App Store Product Page Optimization** (App Store Connect > your app > Product Page Optimization): up to 3
|
||||
treatments against the original, one test at a time, up to 90 days; icon, screenshots and app previews, localized
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ offers, offerCodes, reviewScreenshot, basePlanId, gracePeriod, platforms }] }]`,
|
|||
1. Prerequisites: Apple Paid Applications agreement, banking and tax; Play payments profile and a build with the
|
||||
billing library on a track.
|
||||
2. `storebound check` (limits: Apple name 30 / description 45; Play description 200, up to 4 benefits).
|
||||
3. `storebound apple subscriptions --dry` and `storebound play subscriptions --dry`; read the plan with the owner; then
|
||||
run them in a terminal (they ask). Through MCP (no terminal) they only create what is new; price changes of
|
||||
existing subscriptions wait for the owner.
|
||||
3. `storebound apple subscriptions --dry` and `storebound play subscriptions --dry`; show the plan, then run them
|
||||
yourself (`--yes`). A price change of an existing subscription is a live price: get the owner's yes for it first.
|
||||
Through MCP (no terminal) they only create what is new; price changes of existing subscriptions wait for the owner.
|
||||
4. Review screenshot of the paywall per subscription (`reviewScreenshot`), uploaded by `apple subscriptions`.
|
||||
5. **First subscriptions go with an app version** (and a new group with at least one of its subscriptions):
|
||||
`storebound apple iap-submit --with-version --dry` plans one review submission with the app version, the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue