README is a short front page (about 120 lines) with one real visual per section; every former section moved
unchanged into docs/*.md with a docs/README.md index (journey, rejections, getting-started, commands, growth,
studios, store-art, listing-languages, api, skills, mcp, safety, faq, project). The site tells the same story on one
page: the teaser in the hero, real CLI output as text, the desktop app as a section with light/dark captures of eight
screens and the per-system downloads (desktop/latest.json); /desktop/ redirects to /#download. New capture tools:
tools/site-desktop-shots.ts (fixture-mode desktop frames) and tools/site-term-shots.ts (real CLI output as text and
WebP). tests/docs-links.test.ts checks README, docs and site links resolve.
confirm() prints 'declined: <reason>' and exits 3 whenever the answer is no or nobody can answer (not a
terminal without --yes, serve without the owner's dialog), so no command reports success after declining.
flow run stops at such a step with 'step N declined: <reason>' (status declined), never ok. flow run
--apply --yes passes --yes to write steps only; --yes without --apply is refused. Pitfall 24.
apple build and play build run build.prebuild (or apple.prebuild / play.prebuild) first, once per flow run;
--no-prebuild skips it, --dry only prints it. A Capacitor project's copied public/index.html must then be newer
than the last source commit and <webDir>/index.html, else the build stops (--allow-stale-web overrides). check
warns when stale without a prebuild; the build output and dry plan show the web bundle's sha256 and mtime.
The Capacitor project is also found in a monorepo (apps/native etc.); several ask for play.build.dir /
apple.build.*. Pitfall 23.
A phone-only project aborted with 'no sevenInchScreenshots'. Play requires the 512 icon, the 1024x500 feature graphic and at least 2 screenshots (Play Console Help answer 9866151). play images uploads what exists and prints an info line for missing optional sets; play.tablets true makes missing tablet sets an error in shots render/check/gallery, validate and play images. Pitfall 19.
Google binds its session cookies to the device (Device Bound Session Credentials) and signs out
sessions whose cookies look stolen, which can sign the owner out of their real Chrome. The default is
now storebound's own profile per store; storebound starts Chrome itself (--user-data-dir,
--remote-debugging-port=0, no --enable-automation, navigator.webdriver false) and attaches over CDP.
--use-chrome-session google|apple is an explicit opt-in that warns. /signin/rejected is said plainly.
Google's account widget and cookie rotation frames (accounts.google.com /
ogs.google.com) on a signed-in Play Console no longer count as a sign-in
page. Each detection logs its rule and URL; heartbeats name the page; a
copied Chrome session that lands on a sign-in URL is said plainly; the
sign-in wait gets a watchdog dump, and --debug-dump up to 3 dumps.
Fixtures and tests for the chooser and home with the widget frames and a
top-level accounts.google.com page; pitfall 16.
A real run (sanitized debug dump) showed why the walk stopped after Next:
the data types step is the same "Data Collection" dialog (URL unchanged),
and each checkbox's accessible name is its label run together with its
help text ("NameIncluding first or last name"). Some labels also differ
from Apple's help page ("Purchases", "Other Data").
- labelNames: the exact name, then the label as a prefix that ends where
the help text starts (no lowercase letter follows), so "Name" never
matches "Phone Number...", "Head" never "Health...", "Contact" never
"Contacts...". Used for the data types and the purposes.
TYPE_ALIASES maps Purchase History / Other Data Types to the console's
labels.
- Dialog per step: a section's dialog is also found as the one visible
dialog with a heading of that name.
- Every click and check is bounded (ACTION_MS, 10 s; the scan test now
also rejects clicks without a timeout).
- The flow fixture mirrors the real dialog's structure (dialog/h2 title,
group h3s, input name = Apple's enum, <label> with label + help <p>s,
Save disabled until a type is ticked); no data from the dump. A test
checks every Apple type matches exactly one real-style checkbox.
- Pitfall 15.
Publish is still never clicked; unknown steps still get the watchdog dump.
With the copied Chrome profile, `console fill play-app-record` stopped with
"no developer account named "<name>" (play.developerAccount) on the
chooser" although the name was there: the real "Choose developer account"
rows are not plain /developers/<id> text links (nested spans, icon-font
glyphs, role=button rows with the id in a data attribute, an avatar row
whose id only its click reveals).
- readChooser: every visible clickable row in the page content (header
and navigation left out); the name is the first visible line (icon
fonts, images and aria-hidden parts skipped); the id comes from
/developers/<id> in any attribute, else a data-*id attribute, else ''
(the row is then opened through the account-switch gate and the id is
read from the URL). "Create a new developer account" is not an account.
- matchAccount: exact spelling, then spaces and case aside (Turkish I/ı
folded), then a unique prefix. A case pair (ACME / Acme) needs the
exact spelling; otherwise it stops and lists both with their ids.
- One developer account: picked (a different play.developerAccount is
said). Not found: every visible account is listed with its id.
- The resolved developerId is remembered as before.
Fixtures play-chooser-real.html (the owner's chooser shape, placeholder
names) and play-chooser-one.html; tests for exact, case pair, prefix,
single account and not found.
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.
Play content rating (IARC): storebound now clicks Save draft, then Next,
on each page, like App Privacy's draft saves. Google keeps one draft per
app and IARC gets nothing before Submit, which stays the owner's click.
FORM_BUTTONS, the flow gate (AUTO_DRAFT_SAVE), the console-autofill
skill and the guardrail test are updated; the test answers the open
questions as the owner and checks that Submit on the Summary is never
clicked.
App Privacy stopped at "now click Get Started yourself" and every page
asked the owner to click Next. The owner should not click what
storebound can safely do.
- Every button of every console form is classified (navigation,
draft-save, final-submit) in FORM_BUTTONS (cli/lib/console-forms.ts),
citing Apple's and Google's help pages. A scoped flow gate
(flowAllowed) lets navigation through; the generic click gate stays
absolute for field clicks.
- App Privacy: Get Started, Edit next to Data Types (never the Privacy
Policy Edit), each data type / "Set Up <type>", Next, and the Save
inside the questionnaire dialogs (a draft: Apple publishes only after
Publish, per "Manage app privacy"). Each type's dialog may be one page
or purposes > Next > linked > Next > tracking > Save. It ends with
"review the summary, then press Publish yourself". Publish is never
clicked.
- Play content rating and target audience: Next by itself. Save draft,
Submit, the final Save, Create and Create app stay the owner's.
- An uncertain answer stops the walk on its page (outlined, "answer
needed on ...") until the owner has set it; then it goes on.
Fixture apple-app-privacy-flow.html (first time, ?existing=1, decoys);
tests/console-flow.test.ts with the guardrail that no log line asks the
owner to click a navigation control.
`console fill apple-app-privacy` without apple.appId stopped at "the app
in the list" with "more than one app matches: X | X" for an account with
one app: the Apps grid names each app twice (the icon link's aria-label
and the title link), both opening the same /apps/<id>/... page.
- pickApp tells hits apart by the app they open (/apps/<id>, else the
link target), not by name. Two apps of one name with different targets
still stop and are listed.
- Without apple.appId, but with App Store Connect API credentials, the
app id is looked up from apple.bundleId (GET /v1/apps?filter[bundleId],
as `apple status` does), cached in .storebound/console-app-ids.json, and
App Privacy opens by deep link. Without credentials, or when the lookup
fails, the Apps list by name is used, and the log says so.
Fixture asc-apps-card.html (a card with the name in the title and an
aria-label); tests for both paths.
The two "session cookie survives closing and relaunching storebound's own
profile" tests failed with Playwright's headless shell, which ignores
--restore-last-session. They now live in tests/console-persist.test.ts
and launch the same browser kind console fill uses for its profile (the
resolver's "visible" kind: Google Chrome, else the full Chromium; headless
here, so no window). They skip with the reason only when neither is
installed. All other browser tests keep the fast headless shell. The file
is HEAVY in tools/ci-plan.ts, so it never shares a shard with another
browser suite.