console: Play App content card Saves are the agent's (declaration-save; Send changes for review, Submit, Publish, Restart review stay forbidden), one owner batch per plan with the IARC Terms tick before the run, console plan play-app-content --all, New App fields typed not set, play.appId from the Create app redirect (console verify --url --write) and storebound play app-id across app list pages
This commit is contained in:
parent
1366e7e231
commit
f741c15829
29 changed files with 1029 additions and 165 deletions
|
|
@ -8,8 +8,9 @@ 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.
|
||||
save drafts and Play App content declarations, and verify; the owner only signs in once, does the plan's
|
||||
`ownerBatch` "before" steps (answers, the IARC Terms of Use box) and presses the final button at the end. Hand the
|
||||
owner the whole `ownerBatch` in ONE message before you start, never one item 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
|
||||
|
|
@ -23,26 +24,32 @@ the UI shows. This is the primary mode.
|
|||
|
||||
1. `storebound console plan <form> --json` (MCP: `console_plan`; read-only, offline; `--lookup` asks the App Store
|
||||
Connect API for the app id). It returns:
|
||||
- `ownerBatch` (printed first): EVERY owner step of the plan in ONE list, in the order you need them: `before`
|
||||
(open answers to write into the config, the IARC Terms of Use box with its exact place, the demo account when it
|
||||
is not in `.storebound/credentials.json`) and `after` (the final button, e.g. "Send changes for review");
|
||||
- `start`: the URL (a deep link when `apple.appId`, `play.developerId` or `play.appId` is known, or the ids
|
||||
storebound remembered) and how to reach the form otherwise;
|
||||
- `steps`: plain language plus what to `click` (by visible text) and which `answers` go on each step;
|
||||
- `answers`: every answer with `status` (`certain`, `ask-owner`, `owner-check`, `agreement`), the console's own
|
||||
`label` (curly quotes as shown, `curlyQuotes: true`), `action` (tick / untick / pick / type / choose) and `where`;
|
||||
- `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);
|
||||
- `buttons.neverPress` (Publish, Submit, Create, Create app, Send, Release, "Send changes for review", "Restart
|
||||
review", "Definitions and Examples", "?" ...), `buttons.final` and `buttons.allowed` (navigation, draft saves and
|
||||
Play App content declaration saves);
|
||||
- `uiFacts` (verified facts per form, see below), `driving`, `inPageLoop` (a ready-made in-page helper, see 5) and
|
||||
`verify` (the command and what to capture).
|
||||
|
||||
Forms: `apple-app-record`, `apple-age-rating`, `apple-app-privacy`, `play-app-record`, `play-content-rating`,
|
||||
`play-target-audience` (these also have the scripted `console fill`), and agent-only Play pages:
|
||||
`play-store-settings` (the App category: the Play API has no category field, so `play listing` leaves it "Not
|
||||
selected"), `play-app-content` (every App content card in order, its page, its plan and ONE batch of owner
|
||||
questions), its cards `play-privacy-policy`, `play-ads`, `play-sign-in-details`, `play-advertising-id`,
|
||||
selected"), `play-app-content` (every App content card in order, its page, its plan and ONE owner batch;
|
||||
`--all` / MCP `all: true` puts every card's steps inline in fix order and ends with the one owner list: tick the
|
||||
IARC Terms of Use box (before), Send changes for review (after)), its cards `play-privacy-policy`, `play-ads`, `play-sign-in-details`, `play-advertising-id`,
|
||||
`play-government-apps`, `play-financial-features`, `play-health-apps`, and the first production release:
|
||||
`play-production-countries` and `play-production-release`. `storebound console plan` lists them.
|
||||
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.
|
||||
2. Send the owner the `ownerBatch` of every form you will fill in ONE message before you start (AGENTS.md rule 5): the
|
||||
`ask-owner` answers (write them into the config, so the plan has them; never guess them) and the `before` steps
|
||||
(Play content rating: tick the IARC Terms of Use box on the questionnaire's page 1 first; page 1's Next does
|
||||
nothing until it is ticked). Then run without stopping until the `after` steps.
|
||||
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
|
||||
answer as the sheet says, wait for the next step to render. If the page differs from the plan, adapt (the console
|
||||
|
|
@ -57,13 +64,25 @@ the UI shows. This is the primary mode.
|
|||
The helper finds each control by its label (aria-label, else the nearest parent with non-empty innerText), clicks
|
||||
the inner `[role=radio]` / `[role=checkbox]` of a material control and reads it back; it never clicks buttons and
|
||||
refuses agreements. Press Next / Save yourself afterwards. Never click past a step you have not read.
|
||||
6. Stop before `buttons.final` and tell the owner exactly what to press (App Privacy: review the summary, press
|
||||
Text fields: click and TYPE (key presses); never set `value` programmatically (App Store Connect's New App kept an
|
||||
empty Name / SKU after a `form_input` set, verified 2026-10-13).
|
||||
6. Play App content cards (Privacy policy, Ads, Sign in details, Advertising ID, Government apps, Financial features,
|
||||
Health apps, Target audience, the content rating questionnaire and its Summary, Data safety): press each card's
|
||||
**Save yourself**. Saving a declaration is not public: Google gets it only with the next "Send changes for review"
|
||||
in Publishing overview, which stays the owner's (verified 2026-10-13). The Sign in details demo account: type it
|
||||
from `.storebound/credentials.json` (`reviewDemoAccount`) without echoing it; only when it is not there does the
|
||||
owner type it.
|
||||
7. Stop before `buttons.final` and tell the owner exactly what to press (App Privacy: review the summary, press
|
||||
Publish, then Publish in the "Publish Your App Privacy Responses?" dialog; Play Create app: tick the two
|
||||
declarations, press Create app; content rating: the Summary's Save (not Submit); target audience and the other
|
||||
App content cards: Save; Play production: "Submit N changes for review", then "Send changes for review"; New App:
|
||||
declarations, press Create app; Play App content, content rating, target audience, Store settings and production:
|
||||
"Submit N changes for review", then "Send changes for review" in Publishing overview, once at the end; New App:
|
||||
Create).
|
||||
7. `storebound console verify <form> --from-text -` (MCP: `console_verify` with `text`) with what `verify.capture`
|
||||
says: App Privacy the page's `innerText`, Play Create app the JSON of the capture snippet. Exit 1 / mismatches:
|
||||
8. `storebound console verify <form> --from-text -` (MCP: `console_verify` with `text`) with what `verify.capture`
|
||||
says: App Privacy the page's `innerText`, Play Create app the JSON of the capture snippet; after Create app,
|
||||
`storebound console verify play-app-record --url "<location.href>"` reads the new app's id from the redirect
|
||||
(`/app/<appId>/app-dashboard`), shows the `play.appId` change as a dry diff, and `--write` saves it (an upsert).
|
||||
Missed the redirect: `storebound play app-id` (the app list is paginated, 10 per page, a new app is not on page 1:
|
||||
search the package name or walk the pages, pipe the captures in). Exit 1 / mismatches:
|
||||
fix them in the page (or the config), verify again. `apple-app-record` and `apple-age-rating` verify from the API
|
||||
without text.
|
||||
|
||||
|
|
@ -85,7 +104,12 @@ the UI shows. This is the primary mode.
|
|||
radios did nothing and `form_input` on the native inputs did not update the form ("Select app or game" stayed):
|
||||
click the inner `[role=radio]` with a JS click, then check `aria-checked="true"` and that no "Select …" hint is
|
||||
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`.
|
||||
`/console/u/0/developers/<developerId>/app/<appId>/app-dashboard`: `console verify play-app-record --url <url>
|
||||
--write` puts the id in `play.appId` (2026-10-13: the app list shows 10 apps per page and the new app was not on
|
||||
page 1, so take the id from the redirect).
|
||||
- **App Store Connect New App** (2026-10-13): a programmatic value set (`form_input`, `el.value = …`) on the Name and
|
||||
SKU textboxes left the dialog's React state empty (""); clicking the field and typing worked. Type, don't set
|
||||
value. `console fill` types every text field the same way.
|
||||
- **Play material radios and checkboxes** (Create app, App content, IARC, 2026-10-12): `<material-radio>` /
|
||||
`<material-checkbox>`; click the inner `[role=radio]` / `[role=checkbox]` (or the `<input>`) with a JS click and read
|
||||
`aria-checked` back. Their labels sit in sibling nodes: read the nearest parent with non-empty `innerText`.
|
||||
|
|
@ -96,15 +120,17 @@ the UI shows. This is the primary mode.
|
|||
government-apps, finance (2 steps; the last has "My app doesn't provide any financial features"; Next, Save),
|
||||
health (2 steps; the last step's "Other" box was the no-features answer on that run; Next, Save),
|
||||
target-audience-content (age checkboxes; with 13+ only it went straight to the Summary, no appeal question; Save),
|
||||
content-rating-overview > "Start questionnaire" > content-rating-iarc-questionnaire.
|
||||
content-rating-overview > "Start questionnaire" > content-rating-iarc-questionnaire. Each card's Save is yours
|
||||
(2026-10-13: nothing goes to Google before the owner's "Send changes for review").
|
||||
- **IARC questionnaire** (2026-10-12): page 1 has the email, the category radio and an IARC Terms of Use checkbox (an
|
||||
agreement: the owner ticks it, never you). Then ONE long page of sections; each Yes reveals follow-ups (Violence:
|
||||
agreement: the owner ticks it, never you; page 1's Next does nothing until it is ticked, 2026-10-13, so it is in the
|
||||
owner batch before the run). Then ONE long page of sections; each Yes reveals follow-ups (Violence:
|
||||
humans / non-humans, setting, childlike style, reactions, presentation, blood level, historical war, innocent
|
||||
characters, fierce sounds; Digital Purchases: digital goods, then loot boxes, then player trading; Miscellaneous:
|
||||
user interaction then block / report / moderation / friends-only, location sharing, Nazi symbols, Korea history,
|
||||
terrorism, crimes). The answers come from `console.contentRating.answers` and `.details`, `products[].randomRewards`
|
||||
and `social`. Save, then Next to the Summary with per-authority ratings; its final button is **Save**, not Submit
|
||||
(the owner's). Example: PEGI 7, ESRB E10+, USK 12, ClassInd 18 (paid random items), Google Play 7+.
|
||||
and `social`. Save, then Next to the Summary with per-authority ratings; its button is **Save**, not Submit: yours
|
||||
(a declaration save). Example: PEGI 7, ESRB E10+, USK 12, ClassInd 18 (paid random items), Google Play 7+.
|
||||
- **App Privacy Publish** (2026-10-12): a `<dialog>` "Publish Your App Privacy Responses?" with Cancel / Publish (the
|
||||
owner's); afterwards the page shows "Published a few seconds ago by …", which `console verify` reads.
|
||||
- **Play first production release** (2026-10-12): countries are console-only (`edits.countryAvailability` is
|
||||
|
|
@ -235,11 +261,14 @@ fix. It is not available over MCP: run it from your shell (or the owner uses the
|
|||
6. Multi-page forms: storebound fills a page and clicks its Next itself (App Privacy: Get Started or Edit next to
|
||||
Data Types, Next, the data types' Save, then "Set Up <type>" for each collected type in the Data Types section:
|
||||
purposes > Next > linked > Next > two information pages > Next > Next > tracking > Save; a dialog step it does not know: a debug dump and
|
||||
`paused on "<type>"` until the owner answered it; content rating: Save draft, then Next). It stops on a page only when an answer there is uncertain: it logs
|
||||
`paused on "<type>"` until the owner answered it; content rating: Save draft, then Next). It stops on a page only when an answer there is uncertain, or (content rating page 1) the IARC Terms of Use box is not ticked yet (`agreement needed on …`; Next does nothing until the owner ticks it): it logs
|
||||
`answer needed on "<page>": <the answers>`, leaves them outlined, and goes on by itself once the owner has set
|
||||
each one (a box that should stay empty: click it twice). It never clicks Next past an open question.
|
||||
7. On the last page storebound prints "review every field and press <Save | Submit | Publish | Create> yourself"
|
||||
(App Privacy: "review the summary, then press Publish yourself"). The
|
||||
7. On the last page storebound prints "review every field and press <Submit | Publish | Create> yourself"
|
||||
(App Privacy: "review the summary, then press Publish yourself"). Content rating and target audience: storebound
|
||||
presses the declaration's Save itself and says "storebound pressed Save … press Send changes for review in
|
||||
Publishing overview yourself" (once every App content card is done). Text fields are typed key by key, never set
|
||||
(New App kept an empty Name / SKU after a value set). The
|
||||
command ends when the owner closes the window (`--json` then prints the result with `filled`, `highlighted`,
|
||||
`fallback`, `stoppedAt`).
|
||||
8. Nothing waits silently. While storebound waits it logs `still waiting for <what>, <time>` once a minute. When the
|
||||
|
|
@ -287,8 +316,9 @@ content", "Create and set up your app"):
|
|||
| New App (App Store) | + and New App (Cancel only to leave a team without the bundle id) | **Create**: creates the app record for good |
|
||||
| Age rating (guide only) | nothing (`storebound apple appinfo` sets it by API) | Set Up / Next / Done, if the owner wants to look |
|
||||
| Create app (Play) | Create app on the app list (opens the form); Check availability next to the package name (read-only) | the two **declarations** (agreements, never ticked) and **Create app** in the form: creates the app |
|
||||
| Content rating (Play) | Start; **Save draft** then Next on each page (a draft: IARC gets nothing before the Summary's Save; the owner agreed) | the **IARC Terms of Use** box (an agreement) and **Save** on the Summary (not "Submit", verified 2026-10-12): 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 |
|
||||
| Content rating (Play) | Start; **Save draft** then Next on each page (a draft); **Save** on the Summary (not "Submit"; a declaration save: Google gets it only with the next Send changes for review, verified 2026-10-13) | the **IARC Terms of Use** box (an agreement; ticked by the owner before the run) and **Send changes for review** in Publishing overview |
|
||||
| Target audience (Play) | Start / Manage, Next between the pages, **Save** on the last page (a declaration save) | **Send changes for review** in Publishing overview: sends the declarations to Google |
|
||||
| Other App content cards (agent-only plans) | Start <Name> declaration, Next, **Save** (a declaration save) | **Send changes for review**; the demo account only when it is not in `.storebound/credentials.json` |
|
||||
|
||||
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.
|
||||
|
|
@ -297,9 +327,10 @@ console page changed so that storebound cannot find it, it says so and you click
|
|||
|
||||
Every `[check]` answer, linked-to-identity and tracking for each App Privacy data type (unless `appPrivacy.types`
|
||||
answers them), Developer's Advertising or Marketing, the IARC answers, the target
|
||||
ages, Play's Free or paid and its declarations, the IARC Terms of Use box, the Sign in details username and password,
|
||||
and pressing the final button (App Privacy Publish, the IARC Summary's Save, each App content card's Save, New App
|
||||
Create, Play Create app, Play's Send changes for review).
|
||||
ages, Play's Free or paid and its declarations, the IARC Terms of Use box (before your run), the Sign in details
|
||||
username and password only when they are not in `.storebound/credentials.json`, and pressing the final button (App
|
||||
Privacy Publish, New App Create, Play Create app, Play's Send changes for review). The App content cards' Save and
|
||||
the IARC Summary's Save are yours (nothing goes to Google before Send changes for review).
|
||||
|
||||
## Out of scope
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue