From de6c69695eb52431a63d75779e717c2764468ed6 Mon Sep 17 00:00:00 2001 From: "prompt.ac/@jeffrey" Date: Fri, 24 Jul 2026 00:13:14 -0700 Subject: [PATCH] menuband: record review and market baseline --- slab/menuband/STORE-APP-STORE.md | 11 +++--- slab/menuband/bin/asc.mjs | 34 ++++++++++++++++++- .../menuband/marketing/launch-1.6.5/README.md | 5 ++- .../launch-1.6.5/baseline-2026-07-17.md | 26 ++++++++++++++ 4 files changed, 69 insertions(+), 7 deletions(-) create mode 100644 slab/menuband/marketing/launch-1.6.5/baseline-2026-07-17.md diff --git a/slab/menuband/STORE-APP-STORE.md b/slab/menuband/STORE-APP-STORE.md index 07a853816..af7557703 100644 --- a/slab/menuband/STORE-APP-STORE.md +++ b/slab/menuband/STORE-APP-STORE.md @@ -31,11 +31,11 @@ version is `PREPARE_FOR_SUBMISSION`, `DELETE /v1/appScreenshots/{id}` works. `bin/asc.mjs` wraps the JWT + common queries: `status` / `get ` / `sales` / `analytics`. -**NEXT — v1.6.5 (build 165).** Hardware MIDI input, the sandbox-safe internet -radio side of CDJ Radio, smoother recording cues, and Command-key fixes. The -direct-only Spotify process tap and room-audio host are compiled out of the -App Store target. The release gate is a successful Xcode build/archive plus -the signed sandbox runtime checks in §5. +**IN REVIEW — v1.6.5 (build 165), submitted July 24.** Hardware MIDI input, the +sandbox-safe internet-radio side of CDJ Radio, smoother recording cues, and +Command-key fixes. The direct-only Spotify process tap and room-audio host are +compiled out of the App Store target. Build 165 is `VALID`, the version and +review submission are both `WAITING_FOR_REVIEW`, and automatic release is on. ### Review log @@ -46,6 +46,7 @@ the signed sandbox runtime checks in §5. | 3 | Jul 11 (build 154) | **approved Jul 12** | — | — | Released same day. | | 4 | Jul 15 (build 155) | **approved Jul 16** | — | v1.5.4 post-launch fixes and submission hardening. | Released automatically as configured. | | 5 | Jul 18 (build 156) | **approved + released Jul 18** | — | v1.5.5: menu-bar 3·2·1 count-in, save-anywhere tape export, tape cover art, spoken digits; deduplicated screenshot set. | Released automatically. | +| 6 | Jul 24 (build 165) | **waiting for review** | — | v1.6.5: hardware MIDI, CDJ Radio, scratch/sample capture, recording and command-key polish. | Three unique sandbox-build screenshots verified through the API; automatic release on approval. | ### Screenshot duplication found after release diff --git a/slab/menuband/bin/asc.mjs b/slab/menuband/bin/asc.mjs index cea227753..fbbb60f94 100644 --- a/slab/menuband/bin/asc.mjs +++ b/slab/menuband/bin/asc.mjs @@ -3,9 +3,11 @@ // // node bin/asc.mjs status version states + latest builds // node bin/asc.mjs get raw GET, prints JSON +// node bin/asc.mjs delete DELETE one ASC resource // node bin/asc.mjs sales [YYYY-MM-DD] Sales & Trends daily units (gzip TSV) // node bin/asc.mjs analytics ensure report requests; list reports // node bin/asc.mjs analytics list a report's instances/segments +// node bin/asc.mjs analytics-data print the newest daily CSV // // Auth: the Admin key (App Manager keys can't cloud-sign but CAN read reports). // Signature must be ES256 in ieee-p1363 form — DER signatures are rejected. @@ -51,10 +53,26 @@ async function get(path, raw = false) { return body; } +async function remove(path) { + const res = await fetch(`${API}${path}`, { + method: "DELETE", + headers: { Authorization: `Bearer ${token()}` }, + }); + if (!res.ok) { + let body = ""; + try { body = await res.text(); } catch {} + throw new Error(`${res.status} ${body}`); + } + console.log(`deleted ${path}`); +} + const [cmd, arg] = process.argv.slice(2); if (cmd === "get") { console.log(JSON.stringify(await get(arg), null, 2)); +} else if (cmd === "delete") { + if (!arg?.startsWith("/v1/")) throw new Error("delete path must start with /v1/"); + await remove(arg); } else if (cmd === "status") { const versions = await get( `/v1/apps/${APP_ID}/appStoreVersions?limit=8&fields[appStoreVersions]=versionString,appStoreState,createdDate`, @@ -103,6 +121,20 @@ if (cmd === "get") { console.log( ` ${r[idx("Product Type Identifier")]} units=${r[idx("Units")]} country=${r[idx("Country Code")]} device=${r[idx("Device")] ?? ""}`, ); +} else if (cmd === "analytics-data") { + if (!arg) throw new Error("analytics-data requires a report id"); + const instances = await get(`/v1/analyticsReports/${arg}/instances?limit=200`); + const daily = instances.data + .filter((i) => i.attributes.granularity === "DAILY") + .sort((a, b) => String(b.attributes.processingDate).localeCompare(String(a.attributes.processingDate)))[0]; + if (!daily) throw new Error(`no daily instance for ${arg}`); + const segs = await get(`/v1/analyticsReportInstances/${daily.id}/segments?limit=200`); + for (const segment of segs.data) { + const res = await fetch(segment.attributes.url); + if (!res.ok) throw new Error(`segment download failed: ${res.status}`); + const data = Buffer.from(await res.arrayBuffer()); + process.stdout.write(zlib.gunzipSync(data)); + } } else if (cmd === "analytics") { if (arg) { // List a specific report's instances, then each instance's segment URLs. @@ -162,5 +194,5 @@ if (cmd === "get") { } } } else { - console.log("usage: asc.mjs status | get | sales [date] | analytics [reportId]"); + console.log("usage: asc.mjs status | get | delete | sales [date] | analytics [reportId] | analytics-data "); } diff --git a/slab/menuband/marketing/launch-1.6.5/README.md b/slab/menuband/marketing/launch-1.6.5/README.md index feff177b8..f0e47ad80 100644 --- a/slab/menuband/marketing/launch-1.6.5/README.md +++ b/slab/menuband/marketing/launch-1.6.5/README.md @@ -42,6 +42,10 @@ The first launch is a learning release, not a vanity-metric sprint. Record: Apple campaign reporting suppresses tiny cohorts; a campaign normally needs at least five first-time downloads before it appears. Keep campaign names stable. +The API key cannot reveal the account's provider token, and the available +browser session was not signed in to App Store Connect. Generate links only +after retrieving that numeric token from App Analytics in an authenticated +session. ## Assets @@ -51,4 +55,3 @@ least five first-time downloads before it appears. Keep campaign names stable. - Public page: - App Store: - Advanced direct edition: - diff --git a/slab/menuband/marketing/launch-1.6.5/baseline-2026-07-17.md b/slab/menuband/marketing/launch-1.6.5/baseline-2026-07-17.md new file mode 100644 index 000000000..f5f0ed3e0 --- /dev/null +++ b/slab/menuband/marketing/launch-1.6.5/baseline-2026-07-17.md @@ -0,0 +1,26 @@ +# Pre-1.6.5 App Store baseline + +Snapshot generated July 18 and queried through the App Store Connect Analytics +API on July 24. It covers activity through **July 17, 2026**. + +| Signal | Count | +| --- | ---: | +| App Store impressions | 557 | +| Product-page views | 19 | +| Taps | 9 | +| First-time downloads / purchases | 4 | +| Redownloads | 2 | +| Auto-updates | 1 | +| Gross sales (normalized USD) | $21.54 | +| Developer proceeds (normalized USD) | $14.31 | + +The four purchases were three US and one UK. Two were attributed to App Store +browse/search and two had unavailable source attribution. This is genuine early +traction, but the sample is too small for stable conversion or retention claims. +Do not divide the four purchases by the 19 page views as a headline conversion +rate: one search purchase is reported with `No page`, and Apple's privacy and +attribution thresholds make the event sets non-identical. + +The direct-download channel has a versioned counter and CDN artifact but no +historical report was available in this launch pass. Record its 1.6.5 baseline +after the website deploy. -- 2.51.2