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:
CRTkafa 2026-10-13 05:43:56 +08:00
parent 1366e7e231
commit f741c15829
29 changed files with 1029 additions and 165 deletions

View file

@ -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

View file

@ -24,8 +24,10 @@ products) and answers the compliance facts no file proves, all in one batch at t
App or Game and Free or Paid (material radios: click the inner `[role=radio]`, then no "Select …" hint may be
left), and the declarations, which the owner ticks before pressing Create app. Free can never become Paid.
`storebound console verify play-app-record` checks the form first. Afterwards the app lives at
`/console/u/0/developers/<developerId>/app/<appId>/app-dashboard`: put that app id in `play.appId` (the App
content forms deep-link from it).
`/console/u/0/developers/<developerId>/app/<appId>/app-dashboard`: run `storebound console verify play-app-record
--url "<that URL>"` (dry diff of `play.appId`), then the same with `--write` to save it (the App content forms
deep-link from it). Missed the redirect: `storebound play app-id` (the app list shows 10 per page and a new app is
not on page 1; search the package name, pipe the captures in).
**Owner step after every Create app:** a service account's app-level permissions do NOT cover apps created later.
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
@ -71,11 +73,15 @@ products) and answers the compliance facts no file proves, all in one batch at t
content, Data safety, Advertising ID, Government apps, Financial features, Health apps), each card's page and
start button (aria-label "Start <Name> declaration"), its own plan (`console plan play-privacy-policy`,
`play-ads`, `play-sign-in-details`, `play-content-rating`, `play-target-audience`, `play-advertising-id`,
`play-government-apps`, `play-financial-features`, `play-health-apps`) and ONE batch of owner questions
(`askOwner`): ask them at the start, write the answers into the config (`console.contentRating.details`,
`console.appContent`, `social`, `products[].randomRewards`), rerun the plan. Data safety goes through the API
(step 9). The IARC Terms of Use box and each card's final Save are the owner's (`store-declarations` skill).
Behind a sign-in: the owner types the demo account in Sign in details (`review-access`); with accounts: the
`play-government-apps`, `play-financial-features`, `play-health-apps`) and ONE owner batch (`ownerBatch`,
printed first): the open answers (write them into the config: `console.contentRating.details`,
`console.appContent`, `social`, `products[].randomRewards`; rerun the plan) and, before you start, the IARC Terms
of Use box on the questionnaire's page 1 (an agreement; page 1's Next does nothing until it is ticked). Then
`console plan play-app-content --all` walks every card in order without a stop: you press each card's **Save**
(a declaration save: Google gets nothing before "Send changes for review", the owner's, verified 2026-10-13).
Data safety goes through the API (step 9). Behind a sign-in: you type the demo account from
`.storebound/credentials.json` (`reviewDemoAccount`, never printed; the owner only when it is not there;
`review-access`); with accounts: the
delete-account URL (`account-deletion`); subscriptions: `storebound play subscriptions` (`store-subscriptions`).
11. **UI · Store settings (App category).** `play listing` cannot set it (the Play API has no category field), so a
new app shows "Not selected": set `play.category` (Play's name, e.g. "Strategy"; `storebound check` warns

View file

@ -7,8 +7,9 @@ description: Answer the store compliance forms for a mobile app or game - Google
**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.
the start, and save them in the config; the owner presses only App Privacy Publish, Play's "Send changes for review"
(Publishing overview) and a console form's final Submit / Create, and ticks the IARC Terms of Use box before you
start. Saving a Play App content card is yours (it is not public before Send changes for review).
`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.
@ -29,16 +30,22 @@ CLI: `storebound` (or `bunx storebound` in a project that has it, or `bun <toolc
3. **Play App content (UI, you drive it).** `storebound console plan play-app-content --json` lists every card of
`/app-content/overview` in order (Privacy policy, Ads, Sign in details, Content ratings, Target audience and
content, Data safety, Advertising ID, Government apps, Financial features, Health apps) with its page, start
button (aria-label "Start <Name> declaration") and its own plan, plus ONE batch (`askOwner`) of what the config
does not prove. Ask that batch at the start and write the answers into the config:
button (aria-label "Start <Name> declaration") and its own plan, plus ONE owner batch (`ownerBatch`, printed
first) of what the config does not prove and what the owner does. Hand it over at the start and write the answers
into the config:
- `console.contentRating.answers` and `.details` (the IARC follow-ups each Yes reveals: violence details,
`other` for fear / sexuality / gambling / language / controlled substances / crude humor, player trading, the
user interaction follow-ups, the Miscellaneous questions: Nazi symbols, Korea history, terrorism, crimes);
- `products[].randomRewards` (loot boxes: proven per product; ClassInd rated such a game 18), `social` (chat,
block, report, moderation, friends only, location sharing);
- `console.appContent` (government, financialFeatures, healthFeatures, advertisingId), `reviewAccess`.
The IARC Terms of Use box is an agreement (the owner ticks it). Each card's final Save, and the IARC Summary's Save
(not "Submit"), are the owner's, or yours after the owner's clear yes in chat.
The IARC Terms of Use box is an agreement: the owner ticks it on the questionnaire's page 1 BEFORE your run (it is
in the owner batch; page 1's Next does nothing until it is ticked, verified 2026-10-13). Each card's Save and the
IARC Summary's Save (not "Submit") are yours: a saved declaration goes to Google only with the next "Send changes
for review" in Publishing overview, the owner's one button at the end. `console plan play-app-content --all` walks
every card in order and ends with that owner list. The Sign in details demo account: type it from
`.storebound/credentials.json` (`reviewDemoAccount`) without printing it; the owner types it only when it is kept
out of there.
4. **Apple age rating (API).** `storebound apple appinfo` (all NONE except your overrides, e.g. `advertising: true`).
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

View file

@ -361,8 +361,9 @@ that fails without the fix (see CONTRIBUTING.md).
`social` and `products[].randomRewards` from ONE batch of owner answers (`storebound console plan play-app-content`
lists them), then drive `console plan play-store-settings`, `play-app-content` and its cards,
`play-production-countries` and `play-production-release`. Click the inner `[role=radio]` / `[role=checkbox]`;
run long flows with the plan's `inPageLoop` and poll `window.__log`. Never tick the IARC Terms of Use box; the
Summary's final button is "Save" (the owner's). "Send changes for review" is the owner's real click; managed
run long flows with the plan's `inPageLoop` and poll `window.__log`. Never tick the IARC Terms of Use box (the
owner ticks it before the run: lesson 39); the Summary's button is "Save", and like every App content card Save it
is yours (lesson 41). "Send changes for review" is the owner's real click; managed
publishing is off by default, so approved means live (`play.managedPublishing`).
- **Guard:** the plans above, `check` (category warning, open App content answers), `validate` (category reminder,
"production has 0 countries"), `play status` / `play release` notes; `tests/console-play-plans.test.ts`.
@ -511,3 +512,40 @@ that fails without the fix (see CONTRIBUTING.md).
- **Guard:** `scan` (notes) and `check` (warnings) name every entry that accepts no finding; the credentials template
is empty strings; "your-…", `<…>`, "xxx", "/absolute/path/to/…" and "example" values count as missing everywhere
(`check` warns, `doctor` lists them). `tests/game-report.test.ts`.
## 38. New App: Name and SKU empty after a value set
- **Symptom:** App Store Connect's New App dialog showed the Name and SKU, yet the dialog's state was empty ("").
- **Cause:** the dialog is React: a programmatic value set (`form_input`, `el.value = …`) changes the input, not the
component state; clicking the field and typing works (verified 2026-10-13).
- **Do:** type, don't set value: click the field, type the text key by key, read it back.
- **Guard:** the `apple-app-record` plan (uiFacts, the fill step); `console fill` types every text field (`typeText`);
`tests/console-flow.test.ts`.
## 39. IARC page 1: Next does nothing until the Terms box is ticked
- **Symptom:** on the content rating questionnaire's page 1 Next did nothing, and the agent waited mid-run for the
owner.
- **Cause:** the IARC Terms of Use checkbox gates Next, and it is an agreement only the owner ticks.
- **Do:** hand the owner the plan's `ownerBatch` in ONE message before the run: it has "Tick the IARC Terms of Use
box" with the exact place (Content ratings > Start questionnaire, page 1). Never tick it yourself; if it is still
unticked, say so once and poll it, do not press Next again and again.
- **Guard:** `ownerBatch` in `console plan play-content-rating` / `play-app-content` (printed first); `console fill`
waits for the tick ("agreement needed on …"); `tests/console-play-plans.test.ts`, `tests/console-flow.test.ts`.
## 40. Finding play.appId in a paginated app list
- **Symptom:** finding a new app's Play Console app id took several steps: 10 apps per page, the new app not on page 1.
- **Cause:** the Play API does not return the id; it is only in console URLs.
- **Do:** after Create app read `location.href` (`/app/<appId>/app-dashboard`) and run `storebound console verify
play-app-record --url "<url>"` (dry diff), then `--write` (an upsert of `play.appId`). Missed it: `storebound play
app-id` (search the package name in the list or walk the pages, pipe the captures in), then `--write`.
- **Guard:** `playAppIdInText`, `findPlayAppId`, `upsertNestedString`; `tests/play-app-id.test.ts`.
## 41. App content card Saves are the agent's
- **Symptom:** every Play App content card ended in an owner-only Save, so the owner came back once per card.
- **Cause:** a saved declaration was treated as public. It is not: Google gets it only with the next "Send changes
for review" in Publishing overview (verified 2026-10-13).
- **Do:** press each card's Save yourself (privacy policy, ads, app access, advertising ID, government, financial,
health, target audience, the content rating questionnaire and Summary, data safety). The owner keeps: the IARC
Terms box (before), typing the demo account only when it is not in `.storebound/credentials.json` (otherwise you
type it, never printed), and "Send changes for review" / Submit / Publish / "Restart review" (after).
`storebound console plan play-app-content --all` walks every card and ends with that one owner list.
- **Guard:** `declarationSaveAllowed`, `publishingControl`, `flowAllowed` (`cli/lib/console-forms.ts`), the plans'
`buttons.final` "Send changes for review", `console fill`'s declaration Save; `tests/console-play-plans.test.ts`.