Commit graph

167 commits

Author SHA1 Message Date
CRT
19d34286d5 Feature graphic fits the phone: shots.feature.fit 'contain' (default) sizes the device so its rotated box stays inside 1024x500 with a 24 px margin in both templates, 'bleed' keeps the crop, scale 0.5-1.5, config validated; shots render records measured device boxes (report.json devices) and shots check fails a feature graphic whose device leaves the canvas (warns for a screenshot's front device off a side or the top); tests/feature-fit.test.ts (rotated-box geometry, both templates rendered at 1024x500, bleeding fixture) (pitfall 55) 2026-10-13 09:50:15 +08:00
CRT
0e4f579899 apple build exports each build into build/ios/export/<version>-<build>/ (cleaned first), runs xcodebuild with Apple's tool folders first on PATH (Homebrew rsync 3.x broke Xcode's IPA step: exportArchive Copy failed), shows the IDEDistribution log's real error lines and exits non-zero on any export failure; apple upload fails with exit 1 when the IPA's build number is already on App Store Connect (stale IPA after a failed build), --allow-existing re-checks, --build N picks that build's IPA, release and beta flows use both; doctor flags a non-Apple rsync first on PATH; desktop publish calls rsync by absolute path without --chmod (publishSteps); site download notice per OS (macOS signed and notarized, Windows unsigned for now, Linux unsigned); game-report credential tests hermetic against a machine default profile (pitfalls 53, 54) 2026-10-13 09:45:48 +08:00
CRT
e5f148e534 Onboarding live apps without owner questions for what the stores and the code prove: storebound onboard imports the live products and subscriptions with USD / base prices (catalog diff clean), contact values, the App Review contact and demo account (credentials.json, masked), sign-in for review from Apple's review detail and auth code, and the account deletion page from the app's site; App Store keywords count characters (live fields up to 265 bytes accepted); validate accepts the 6.5-inch iPhone set and Play's default-language graphics fallback; Play Reporting API off gives the project's enable link and apps list falls back to local apps; accounts default <profile>; store-only apps (apps add --store --app-id) shown read-only in the desktop (pitfalls 43-52) 2026-10-13 07:25:01 +08:00
CRT
d2ce185441 One product per machine: the CLI and the desktop app share one version, the store accounts and the app folder list
- one version: package.json's version is the desktop app's too (desktopVersion removed); tools/desktop-version.ts
  keeps the plugin manifests and the app's copies equal, desktop-release publish refuses another version, release
  order app first then npm publish; the unpublished desktop 0.1.0 candidate is noted in the docs and CHANGELOG
- storebound desktop installs (per user, no admin: macOS DMG -> /Applications or ~/Applications, Windows NSIS /S,
  Linux AppImage + .desktop with the storebound:// handler), updates an older app, notes a newer one (downgrade only
  with --force), asks once ([Y/n], --yes, exit 3 without a terminal), opens on the folder; --dry / --json / --download;
  the install steps are pure plans (cli/lib/desktop-install.ts); the version's own manifest dl/<version>/latest.json
- credentials: one store, the CLI's credential profiles in ~/.storebound/credentials; the desktop writes and reads
  them (profiles.rs, files 0600), moves old keychain accounts into profiles on first start, shows profiles the CLI
  made; precedence env > named profile > project file > default profile; config `account`, "account" in the
  project's credentials.json; storebound accounts list | import (dedup by key id / service account e-mail, key files
  copied 0600, project file keeps keystore and review contact, backup, --dry, never prints values) | use
- app folders: one list ~/.storebound/projects.json shared by the desktop (registry.rs), storebound desktop,
  apps folders | add | remove, ws init and ws without a workspace file
- desktop: notice when a folder pins another storebound version; storebound-desktop --version
- tests: version drift, desktop decisions and per-OS plans, credential precedence and import, registry (TS + Rust),
  keychain migration and profile round trip (Rust), boot check with old keychain state and the new shared state
2026-10-13 06:17:37 +08:00
CRT
bba46b5c7f apple testflight distribute: a build's groups read per group (GET /v1/betaGroups/{id}/relationships/builds) instead of GET /v1/betaGroups?filter[builds]=, which App Store Connect refuses with 400 although the spec declares it; internal all-builds groups reported as already available and never sent the build; a re-run adds nothing; configured groups missing on App Store Connect point at groups sync, unknown ones list what exists; APPLE_LIVE_REJECTED (refused by storebound api too), tests/asc-query-guard.test.ts checks every App Store Connect GET with a query in cli/ against the spec's declared parameters, and the fake App Store Connect answers 400 to undeclared or live-refused parameters (pitfall 42) 2026-10-13 06:03:16 +08:00
CRT
f741c15829 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 2026-10-13 05:44:29 +08:00
CRT
1366e7e231 scan, privacy answers and credentials from a second game's first release (lessons 35-37): review-prompt needs rating context, not a bare "rate"; account signals skip import lines and module paths, config-only accounts say "from config"; accounts.inApp without deletion code stays a medium 5.1.1(v) finding; privacy-manifest --propose builds NSPrivacyCollectedDataTypes from appPrivacy.types and check warns on an empty list; appPrivacy.types is authoritative in the App Privacy sheet (unlisted = not collected), ad / support / AR types default to not collected without tracking or ad SDKs; Play advertising ID from SDKs, the AD_ID permission, app-ads.txt or the flag, never from a Device ID alone; scan.ignore[].evidence and warnings for entries that match nothing; empty credentials template, placeholder values count as missing (check, doctor) 2026-10-13 05:39:09 +08:00
CRT
ba8cfd2594 0.7.0: version (package, plugin and extension manifests), changelog section with summary; check no longer counts owner-only App content steps (IARC Terms, demo account typing) as missing config answers; the check shot shows a ready project (init plus icons, apple.name, App content answers, demo account): all good 2026-10-13 04:19:39 +08:00
CRT
36a8bf9625 CLI runs on Node 20+: npx storebound (bunx keeps working)
- cli/lib/rt.ts: the runtime layer on node: modules (spawn / spawnSync with Bun's defaults, exit codes and
  "Executable not found", which with PATHEXT, sleep, serve, Glob, hasher, gunzip, stdin, SQLite, packageRoot,
  config imports with a type-stripping fallback for Node 20); every Bun.* use in cli/ goes through it
- tools/gen-embedded.ts -> cli/lib/embedded.ts: templates/, cli/shots/*.html and Play's Data safety form embedded
  (replaces Bun text imports; the bundle and the compiled sidecar carry them), checked fresh by bun run ci
- package.json: bin dist/storebound.mjs (Node ESM bundle, tools/build-node.ts, prepack), engines node >=20
- bun run ci: node bundle + node smoke (real node: --version, help, check same as Bun, scan, release plan --help,
  init, MCP handshake + tool call); Forgejo CI sets up Node 20; tests/node-compat.test.ts guards cli/
- install writes npx MCP commands when run with Node; bin/storebound falls back to Node
- docs: npx storebound init (Node 20+) or bunx storebound init
2026-10-13 04:03:28 +08:00
CRT
710c3a53d0 README, docs and site: one story (the whole job, no avoidable rejections, the desktop app, your AI, install)
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.
2026-10-13 03:29:59 +08:00
CRT
b9579e2a2e shots / console: resolve playwright only from an installed node_modules copy; in a project without playwright Bun auto-installed the newest one into its global cache, whose browsers were never downloaded (capture-web on Linux CI: 'headless shell: not installed'; macOS hid it with Google Chrome) 2026-10-13 02:55:12 +08:00
CRT
56591f4118 ci on Linux: --no-sandbox for the Chromium storebound starts itself as root on Linux or in a container (sandboxArgs; Chromium refuses root without it), never on macOS / Windows / a normal user; workflow caches Playwright's browsers; capture-web prints the capture's stderr when a run fails 2026-10-13 02:51:48 +08:00
CRT
9ba8471002 ci speed: desktop boot check runs its cases in parallel (one browser, killed at the end; a page per case; condition waits instead of fixed sleeps: element, text or a quiet window of host calls and DOM); shots capture / render close the browser with a 3 s cap, then kill it; console engine waits injectable for tests (WAITS / engineWaits: poll rounds, a missing step ends once its loaded page stays quiet, team switch settle, field-miss grace), fillPage looks up each data type's dialog once per round and skips dialog sections when no dialog is open; browser tests run 4 at a time per file (testScope().concurrent with a scope per test, --max-concurrency in ci), 20 ms rounds; capture-web counts boots per test and runs its browser tests concurrently; console-session / -persist Chrome tests concurrent; recorded test timings smoothed (mergeTimings) so one loaded run does not skew the shard split 2026-10-13 02:22:25 +08:00
CRT
7e09947e62 console verify App Privacy: real page text (category-only summary sections, ' | ' joined lines, Apple's commas); tracking label without 'data data'; Play Data safety page path confirmed 2026-10-13 01:38:50 +08:00
CRT
33eb24a3dc apple submit --build <n> (first submission, the resubmit steps; plan table with --json under serve); desktop owner actions to send for review: owner.apple_submit, owner.apple_resubmit, owner.apple_iap_submit, owner.play_production, and the price gate owner actions (owner.prices_play_products / _play_subscriptions / _apple_subscriptions; owner.prices_import passes --allow-price-changes after the dialog); OWNER_ALLOWED_ARGS ties each forbidden flag to its one action, dry runs never carry owner flags, MCP still has no submit or production release; submit dialog text in the host; system.tools androidSdk, project.inspect playRelease, declarations dataDeletion 2026-10-12 12:08:07 +08:00
CRT
2e7dd44ae6 play build versionCode source check: follow a variable (def / ext. / val) to its definition; a variable read from the property is not flagged 2026-10-12 11:34:41 +08:00
CRT
0b1451800c apple iap-submit: DEVELOPER_REJECTED IAP / subscription / group versions (left by a canceled submission) are submitted as they are, plan says 'add (developer rejected, re-submitted as is)', --new-version only for APPROVED / REJECTED, empty draft reused; fake ASC models cancel and re-add. play build / check: warn before Gradle when defaultConfig does not read -PversionCode / -PversionName, with the exact Groovy / Kotlin line (built with AGP 8.13); android.injected.version.code does not override bundleRelease; post-build versionCode mismatch is a hard stop. play-production-release plan: 'Do you want to restart your review?' dialog, Restart review is never-press. Pitfalls 31-33 2026-10-12 11:32:05 +08:00
CRT
41d2ffcc24 apple testflight groups: bare lists the groups and what the config would create (read-only); groups sync (or --yes) creates; flows: bare = read, sync = write; MCP tool runs groups sync 2026-10-12 10:48:59 +08:00
CRT
1724296e59 apple resubmit: REJECTED review submission items are marked resolved before the submit (PATCH reviewSubmissionItems resolved: true; the version item by default, IAP / subscription items with --resolve-iaps), plan table 'mark resolved' rows; on 409 'not ready yet' the items are re-read and a REJECTED item out of scope stops the run at once naming it and how to resolve it, backoff only when none is left; an empty READY_FOR_REVIEW draft is never canceled (409 'not in cancellable state'): left as is, no cancel command, apple status labels it harmless and treats the cancel 409 as such; fake ASC blocks submit on REJECTED items and refuses to cancel empty drafts. Pitfall 30 2026-10-12 10:45:05 +08:00
CRT
0da5ee9d01 apple resubmit after a rejection: iap-submit reuses the open review submission (UNRESOLVED_ISSUES gets only missing items and is resubmitted, a draft is reused, one waiting for or in review means nothing is sent), never a second draft; 409 ITEM_PART_OF_ANOTHER_SUBMISSION names the other submission instead of the list-lag message, a draft the run created is canceled and the named one used; submit retried with backoff and heartbeat while Apple says not ready yet; new apple resubmit --build <n> (build by number, plan table, --yes); apple status lists UNRESOLVED_ISSUES items and the resubmit command. Pitfall 30 2026-10-12 10:34:12 +08:00
CRT
c8213be2b6 ITMS-91064: NSPrivacyTracking and NSPrivacyTrackingDomains must agree in every privacy manifest (true needs domains, domains need true); check, scan and privacy-manifest fail on either mismatch with the exact ITMS text; App Privacy tracking no longer demands the app manifest's true: SDK manifests that declare tracking (Pods, frameworks, SwiftPM, Carthage, plugins, the built IPA) are info, known tracking SDKs info, else a warning; privacy-manifest --propose writes true only with appPrivacy.trackingDomains; apple upload checks every manifest in the IPA (XML or binary) before any network call, apple build after the export. Pitfall 29 2026-10-12 10:27:21 +08:00
CRT
b7bfe89151 Play console steps without an API as agent plans: play-store-settings (App category; play listing cannot set it), play-app-content (every card in order, one owner batch) and its cards (privacy policy, ads, sign in details, advertising ID, government, financial, health), play-production-countries and play-production-release; IARC plan with the Terms of Use agreement, follow-ups (console.contentRating.details, products[].randomRewards, social) and the Summary's final Save; config play.category / countries / managedPublishing, console.appContent; check, validate, play status and play release reminders; inPageLoop helper and material checkbox clicks; App Privacy published signal; first IAPs via apple iap-submit --with-version. Pitfalls 27, 28 2026-10-12 10:16:34 +08:00
CRT
dbd9f2973c play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER is the general 'can users request deletion?' question; a delete-account URL answers yes (with PSL_DATA_DELETION_URL), dataSafety.dataDeletion for apps without one; check flags a no next to a delete-account URL 2026-10-12 09:46:58 +08:00
CRT
e01a27d7b7 price changes of existing products need --allow-price-changes (play products, play/apple subscriptions, prices import): --yes and flow run --apply --yes confirm creates, first prices and other updates only; without the flag the run writes the rest, names each held change and exits 3 (declined), dry runs mark them owner, flows refuse the flag; lib/price-gate.ts, tests/price-gate.test.ts. CLI wording: console fill leaves what it cannot open or fill to the calling agent's browser tool (console plan / verify) instead of 'yourself'; other 'by hand' output points at the config; do-it-dont-ask test scans cli/ output 2026-10-12 09:38:57 +08:00
CRT
b5b8f2da9d play data-safety: PSL_SUPPORT_DATA_DELETION_BY_USER as Play's single choice (partialDeletion true | false | 'auto90'), drop the removed PSL_DATA_COLLECTION_USER_REQUEST_DELETE (deletionRequest deprecated, check notes it); ship Google's empty form (cli/data/play-data-safety-form.csv, exported 2026-10-12), take every Answer requirement from it and report pairs not in it (formPairIssues) in check, declarations and play data-safety. Pitfall 21 2026-10-12 09:34:12 +08:00
CRT
fc524cd2d4 play build: find the Android SDK like Android Studio (ANDROID_HOME, ANDROID_SDK_ROOT, sdk.dir, default folder), pass it in the env, stop before Gradle when missing; doctor shows it. apple upload: size, per-part lines, 20 s heartbeat (api, altool, processing wait), per-part and per-call timeouts, --timeout exits 7 with the resume hint. Pitfall 25 2026-10-12 08:59:45 +08:00
CRT
366362d62b flow run: a declined confirmation stops the flow; --apply --yes confirms write steps
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.
2026-10-12 08:51:58 +08:00
CRT
5fbb9e63e3 build.prebuild and a Capacitor web-asset staleness guard for apple build / play build
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.
2026-10-12 08:51:38 +08:00
CRT
78be1304ec AAB manifest: read aapt2 Resources.proto field numbers (element name 3, attribute 4, child 5); real AGP bundles failed with 'AAB manifest without package / versionCode' 2026-10-12 08:45:43 +08:00
CRT
720cb2a13a play images: same languages as play listing (drafts skipped unless --include-drafts); a language with no Play listing (404) is skipped with an info line, never fatal 2026-10-12 08:45:43 +08:00
CRT
97ab76e9c8 play data-safety: write the conditional required rows (PSL_ACCOUNT_DELETION_URL from accounts.deletionUrl, PSL_SUPPORT_DATA_DELETION_BY_USER from dataSafety.partialDeletion, PSL_DATA_DELETION_URL); a rule table checks every conditional row in check, declarations and --dry before Play answers 400 2026-10-12 08:40:36 +08:00
CRT
c9a7f095c4 console: agent-first mode (console plan / console verify), verified App Privacy and Play Create app facts
- `storebound console plan <form> [--json] [--lookup]`: read-only plan for an AI agent that drives the browser
  itself: start URL (deep links), ordered steps, answer sheet with the console's exact labels (certain / ask owner,
  curly quotes noted), never-press list, verified UI facts, driving guidance (in-page async loop + window.__log),
  verify instructions. All six forms.
- `storebound console verify <form> [--from-text <file|->]`: App Privacy per-type summaries from page text, Play
  Create app from input states, content rating / target audience summaries, App Store record and age rating from
  the API; exit 1 on a mismatch.
- MCP: console_plan, console_verify (read-only); console fill stays off MCP.
- App Privacy (verified 2026-10-12): two information steps, unlabeled purpose checkboxes (nearest parent text),
  "Definitions and Examples" never pressed; fixture and engine follow.
- Play Create app (verified 2026-10-12): /developers/<id>/create-new-app, App package name + read-only Check
  availability, material-radio inner [role=radio] click, app dashboard URL and play.appId, service account
  "Add app" as an owner step.
- console-autofill skill rewritten agent-first; agents-core rule 10; README; pitfalls 12, 18 (confirmed sign-out),
  19; CHANGELOG; play-first-release.
2026-10-12 08:39:12 +08:00
CRT
a9261a8052 play images: tablet, TV and Wear sets are optional; play.tablets switch (default: tablet renders exist); a missing optional set never deletes Play's images without --prune
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.
2026-10-12 08:21:03 +08:00
CRT
18fde37b9b console fill: labels match straight and curly quotes (Developer’s Advertising, the user’s identity); an App Privacy dialog step with no inputs (the definitions page) is passed with Next 2026-10-12 07:52:13 +08:00
CRT
0035931734 console fill: never copy Google session cookies by default (device-bound); own profile in a Chrome started without automation switches
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.
2026-10-12 07:46:38 +08:00
CRT
e0bef82b06 console fill apple-app-privacy: set up each data type from the real page ('Set Up <type>' is a plain text, clicked by its exact text in the Data Types section), fill its dialog step by step, dump and pause on an unknown step; '?' and Publish never clicked 2026-10-12 07:38:25 +08:00
CRT
3aedf9e137 console fill: sign-in only by the top-level URL, the main frame's form or an Apple sign-in frame
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.
2026-10-12 07:29:11 +08:00
CRT
b48407115e console fill: checkbox / radio ticks are gated on agreements only (help text like 'saved place in a game' no longer blocks Product Interaction); buttons keep the full word gate 2026-10-12 07:19:50 +08:00
CRT
59150c1186 console fill apple-app-privacy: fit the Data Collection dialog to the real console
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.
2026-10-12 07:17:15 +08:00
CRT
8b669f5c86 console fill play-app-record: read the real account chooser, match names loosely
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.
2026-10-12 07:12:05 +08:00
CRT
81313b6fa4 console fill: no silent waits; an unknown page gets a debug dump and a bounded stop
A real `console fill apple-app-privacy` clicked Next onto a console page
the engine did not recognise and logged nothing for 8 hours.

- Step watchdog: after a click, or while the form is expected, no known
  page within --step-timeout seconds (default 30) -> "the page after
  "Next" is not a page storebound knows ... Buttons there: ...", a debug
  dump, and the manual steps. It keeps watching, but 20 min without
  progress closes the window and exits 1.
- A heartbeat line every minute while waiting (also during sign-in); the
  final review wait is bounded (2 h) with a reminder every 10 min.
- Debug dump (cli/console/debug.ts) in .storebound/console-debug/
  <form>-<time>/: page.json (URL without query, headings, dialogs, every
  visible control with role and name), page.html (rebuilt from a clone:
  no scripts, values, hidden inputs or non-whitelisted attributes) and a
  small screenshot. Emails, phone numbers and the header / account area
  are replaced; cookies, storage and tokens are never read.
  --debug-dump writes one at every step for bug reports.
- Guardrail tests: an unknown-page fixture (dump sanitized, bounded exit)
  and a scan of cli/console for while loops without a deadline and
  Playwright waits without a timeout (one waitForLoadState fixed).
- Pitfall 14 (docs/pitfalls.md, store-pitfalls skill); the
  console-autofill skill says how to send a dump.
2026-10-12 07:08:10 +08:00
CRT
ece6644522 console fill: the content rating's Save draft is clicked too (the owner agreed)
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.
2026-10-12 06:57:26 +08:00
CRT
8ffc83bb39 console fill: walk the whole form; the owner only reviews and presses the final button
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.
2026-10-12 06:51:01 +08:00
CRT
b39e44e6ab console fill: one app shown twice is one app; App Privacy opens by app id via the API
`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.
2026-10-12 06:32:21 +08:00
CRT
e21e274c2a browser: one launch resolver; console fill never reports a hidden error
`console fill --fresh-profile` failed with "Executable doesn't exist ...
chromium-1187" when only Playwright's headless shell was downloaded,
although Google Chrome was installed (also with STOREBOUND_CHROME set).
The Chrome launch did run, but failed because an earlier storebound run
still held the profile, and the fallback rethrew the FIRST error.

Every launch (renders, captures, console profile and copy modes, the
desktop sidecar) now goes through one resolver that checks the exact
executable before trying it:
- headless: STOREBOUND_CHROME, headless shell, full Chromium, Chrome
- visible / persistent: STOREBOUND_CHROME, Google Chrome, full Chromium
  (channel "chromium"); never the headless shell
- copy mode: Google Chrome only
A missing browser is skipped; an installed one that fails reports its own
error; nothing usable names what was looked for plus the doctor /
playwright install hint. A profile whose SingletonLock names a live
process is reported before launching.
2026-10-12 06:17:19 +08:00
CRT
db363be37b flags: regenerate (check reads the iOS project through the scan modules) 2026-10-12 05:27:03 +08:00
CRT
d531626836 Merge remote-tracking branch 'origin/main' into play-app-record
# Conflicts:
#	CHANGELOG.md
2026-10-12 05:26:34 +08:00
CRT
04fb0089b5 Merge remote-tracking branch 'origin/main' into play-app-record
# Conflicts:
#	CHANGELOG.md
#	docs/pitfalls.md
#	skills/store-pitfalls/SKILL.md
#	tests/console-fill.test.ts
2026-10-12 05:24:52 +08:00
CRT
7746a984ec Merge remote-tracking branch 'origin/main' into shots-liga
# Conflicts:
#	CHANGELOG.md
#	cli/index.ts
2026-10-12 05:24:19 +08:00
CRT
af08d7113a shots check: ligatures no longer read as system-font glyphs (probe spans shaped as one run); --help on every command and group, unknown flags rejected before anything runs
Root cause: the per-character font probes were inline spans side by side, so Chrome shaped f + i into the fi ligature across them and the lone i probe reported no glyph of ours. Each probe is now its own block. The Google Fonts text= subsets keep the GSUB ligatures; regression test with a real Montserrat text= subset.

--help / -h prints the command's usage and exits 0 before any config, render or network; unknown flags exit 2 with the usage (cli/data/flags.json from tools/gen-flags.ts). Command tables moved to cli/commands.ts; ads apple reachable again; shots render --scenes rejects unknown ids at once.
2026-10-12 05:23:37 +08:00