Skip to content

Commit 084465a

Browse files
docs(ahbg): close post-merge Play release truth gaps (#28)
* docs(ahbg): restore complete Play release blockers * docs(ahbg): correct RevenueCat project and entitlement boundaries * docs(ahbg): expose runtime and entitlement blockers
1 parent d186fb9 commit 084465a

3 files changed

Lines changed: 169 additions & 68 deletions

File tree

ahbg/submission/GOOGLE_PLAY_RUNBOOK.md

Lines changed: 64 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,17 @@ default), and a signed AAB.
1010
- RevenueCat `purchases:10.19.1` only (no Galaxy module); ordinary
1111
`PurchasesConfiguration` is the correct Play configuration.
1212
- Package `org.interdependency.ahbg`; entitlement `benchmark_lab` unchanged.
13-
- Entitlement lookup is wired, but **purchase initiation and explicit restore
14-
controls are not yet implemented**. Do not call the Play billing gate complete
15-
until the app can fetch the offering, launch the purchase, and call
16-
`restorePurchases` through a user-visible path.
13+
- Entitlement lookup exists, but the Android/WebView surface currently reads a
14+
synchronous Boolean while RevenueCat refreshes customer info asynchronously.
15+
- Purchase initiation and explicit restore controls are not yet implemented.
16+
- Verified client-to-runtime entitlement transport and enforcement of the
17+
premium operations are not yet implemented.
18+
- `BuildConfig.RUNTIME_URL` points at the intended production host, but a source
19+
constant is not deployment evidence. Production TLS/reachability and the
20+
AHBG runtime service still require end-to-end acceptance.
21+
22+
Do not call the Play billing or publication gate complete until those repository
23+
boundaries and the live-account boundaries below have been verified.
1724

1825
## 1. Play Console
1926

@@ -23,13 +30,17 @@ default), and a signed AAB.
2330
testers for at least 14 days before production access.
2431
2. Create the app (`org.interdependency.ahbg`) and complete the store listing
2532
with `STORE_LISTING.md`, `PRIVACY_POLICY.md`, icon, and screenshots.
26-
3. Complete the mandatory **App content** declarations before production:
33+
3. Complete the mandatory **App content** declarations before production,
34+
including the applicable "none" declaration when the app has no such
35+
features:
2736
- Data safety;
2837
- public privacy-policy URL;
2938
- ads declaration;
3039
- app-access declaration/instructions;
31-
- target audience and content declarations; and
32-
- content-rating questionnaire.
40+
- target audience and content declarations;
41+
- content-rating questionnaire;
42+
- Financial features declaration; and
43+
- Health apps declaration.
3344

3445
## 2. Release artifact (Play-native AAB)
3546

@@ -71,14 +82,34 @@ provisioned). Upload the signed AAB as the first internal/closed test release.
7182
activate.
7283
6. In RevenueCat, map product `ahbg_benchmark_lab` → entitlement
7384
`benchmark_lab` → default offering.
74-
7. Copy the Google Play app's RevenueCat **public SDK API key** (`goog_...`)
75-
into the Android build. `rc_...` identifies RevenueCat project resources;
76-
it is not the Google Play Android SDK key.
85+
7. Record the RevenueCat project ID exactly as shown by RevenueCat; v2 project
86+
IDs use the `proj...` form. This is project metadata, not an Android SDK key.
87+
8. Copy the Google Play app's RevenueCat **public SDK API key** (`goog_...`)
88+
into the Android build.
7789

78-
## 5. Sandbox purchase + restore + persistence verification
90+
## 5. Repository billing and entitlement gate
7991

80-
This gate is **repository-blocked until purchase and restore controls are
81-
wired**. Once that code exists:
92+
Sandbox verification is **repository-blocked** until all of these are real:
93+
94+
1. fetch the current RevenueCat offering/package and initiate purchase of
95+
`ahbg_benchmark_lab` from a user-visible control;
96+
2. expose an explicit restore control using RevenueCat restore and handle
97+
success/cancel/error outcomes;
98+
3. notify/refresh the WebView when asynchronous customer-info refresh changes
99+
`benchmark_lab`, including on cold start rather than relying on one early
100+
synchronous read;
101+
4. carry a server-verifiable entitlement claim to the runtime and enforce it at
102+
the premium operations instead of changing only a local status label; and
103+
5. deploy the production runtime and verify TLS, `board.html`, session creation,
104+
plan/state calls, entitlement checks, and the premium gate through the exact
105+
production URL.
106+
107+
Do not replace these with a local Boolean, a documentation assertion, or an
108+
unverified client field.
109+
110+
## 6. Sandbox purchase + restore + persistence verification
111+
112+
Once section 5 exists:
82113

83114
1. Play Console → Settings → License testing: add the Google account that will
84115
perform the billing test. Test-track membership alone does not make a
@@ -87,19 +118,24 @@ wired**. Once that code exists:
87118
install the Play-delivered test release.
88119
3. Verify free tier: basic play and external harness connectivity work.
89120
4. Fetch the current RevenueCat offering and initiate purchase of
90-
`ahbg_benchmark_lab`; confirm `benchmark_lab` unlocks.
121+
`ahbg_benchmark_lab`; confirm the verified runtime premium surface unlocks.
91122
5. Invoke the app's explicit restore path; confirm the entitlement re-activates
92-
for the same store account.
93-
6. Force-stop and relaunch; confirm the entitlement remains correct.
94-
95-
## 6. Production
96-
97-
1. Complete the required closed test if the account is subject to it.
98-
2. Complete all App content declarations and resolve every Play Console
123+
for the same store account and the WebView receives the refreshed state.
124+
6. Force-stop and relaunch; confirm asynchronous customer-info refresh restores
125+
the correct state without requiring a page reload or second app start.
126+
7. Exercise one premium operation and prove the runtime rejects it without a
127+
valid entitlement and accepts it with the verified entitlement.
128+
129+
## 7. Production
130+
131+
1. Deploy the production AHBG runtime at the exact configured HTTPS URL and run
132+
the end-to-end health checks in section 5 from a release-equivalent client.
133+
2. Complete the required closed test if the account is subject to it.
134+
3. Complete all App content declarations and resolve every Play Console
99135
publication blocker.
100-
3. Apply for production access, promote the release, obtain the public Play
136+
4. Apply for production access, promote the release, obtain the public Play
101137
Store URL.
102-
4. Use that URL as the Devpost entry.
138+
5. Use that URL as the Devpost entry.
103139

104140
## Galaxy (deferred/optional)
105141

@@ -109,7 +145,8 @@ and follow the archived Galaxy notes.
109145

110146
## hmmm
111147

112-
The repository can prepare the AAB and entitlement boundary, but Play account
113-
approval, live service credentials, store policy declarations, and the real
114-
billing transaction remain external. Purchase/restore UI is still repository
115-
work and must be completed before sandbox verification.
148+
The repository can build the AAB and observe an existing RevenueCat entitlement,
149+
but acquisition, asynchronous UI refresh, verified runtime enforcement, and
150+
production-runtime acceptance remain repository work. Play account approval,
151+
live service credentials, policy declarations, and the real billing transaction
152+
remain external.

ahbg/submission/REVENUECAT_PROVISIONING.md

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22

33
The entitlement-check integration exists (`Entitlements.kt` + runtime
44
`entitlements.py`). Live provisioning needs the RevenueCat dashboard, Play
5-
Console, and Google Cloud. Purchase initiation and explicit restore controls
5+
Console, and Google Cloud. Purchase initiation, explicit restore controls,
6+
asynchronous WebView refresh, and verified runtime entitlement enforcement
67
remain repository work and are called out separately below.
78

89
## Dashboard + Play connection
910

1011
1. Create the production project in RevenueCat.
11-
- Record the **project id** here once created: `rc_<TO_FILL>`.
12+
- Record the **project id** exactly as RevenueCat shows it; v2 project IDs
13+
use the `proj...` form.
1214
- This project id is not an Android SDK API key.
1315
2. Add a **Google Play** app (`org.interdependency.ahbg`).
1416
3. Google Cloud Console:
@@ -41,41 +43,73 @@ remain repository work and are called out separately below.
4143
10. RevenueCat `10.19.1` core supports Google Play through the ordinary
4244
`PurchasesConfiguration`; no Galaxy store module is required.
4345

44-
## Repository billing controls — not complete
46+
## Repository acquisition controls — not complete
4547

4648
Before the live Play billing gate can run, AHBG must expose user-visible
4749
operations that:
4850

4951
1. fetch the current RevenueCat offering/package for `ahbg_benchmark_lab`;
5052
2. initiate the purchase and handle success/cancel/error outcomes; and
51-
3. invoke `Purchases.sharedInstance.restorePurchases`, then refresh the
52-
entitlement state.
53+
3. invoke RevenueCat restore, then refresh the entitlement state.
5354

5455
`getCustomerInfo` / `isBenchmarkLabUnlocked()` alone can observe an existing
5556
entitlement but cannot acquire or explicitly restore one.
5657

58+
## Repository entitlement delivery — not complete
59+
60+
The current store initializes `benchmarkLabUnlocked` to false and refreshes it
61+
asynchronously. The WebView bridge exposes only a synchronous Boolean read.
62+
Therefore a cold start can read `false` before RevenueCat answers and never
63+
learn that the entitlement became active.
64+
65+
Before persistence is called complete:
66+
67+
1. publish an explicit entitlement-state update from the RevenueCat callback to
68+
the WebView (or provide an equivalent deterministic refresh path);
69+
2. update the premium UI when that state changes without requiring a restart;
70+
3. carry a server-verifiable entitlement claim across the Android/runtime
71+
boundary; and
72+
4. enforce `benchmark_lab` at the actual premium runtime operations, not only
73+
at a local label or client-side control.
74+
75+
The client must not be the authority for its own premium claim.
76+
77+
## Production runtime — not complete
78+
79+
`BuildConfig.RUNTIME_URL` names the intended HTTPS host, but the repository does
80+
not thereby prove that the AHBG service is deployed, reachable, or serving the
81+
same runtime contract. Before Play publication, verify the production URL from
82+
a release-equivalent client: board load, session creation, plan/state calls,
83+
entitlement verification, and one denied/allowed premium operation.
84+
5785
## Verify (gate items)
5886

5987
Before any billing transaction, configure the purchasing Google account under
6088
Play Console **License testing** and use that same account to accept/install the
6189
test-track build. Test-track membership alone is not a sandbox guarantee.
6290

63-
After the repository billing controls above exist:
91+
After the repository acquisition, entitlement-delivery, and production-runtime
92+
boundaries above exist:
6493

6594
- **Free tier**: no purchase → inactive entitlement; Benchmark Lab locked;
6695
basic play and harness connectivity work.
67-
- **Purchase**: the license-test transaction activates `benchmark_lab` and the
68-
premium surface unlocks.
96+
- **Purchase**: the license-test transaction activates `benchmark_lab`, the
97+
asynchronous update reaches the WebView, and the verified runtime premium
98+
surface unlocks.
6999
- **Restore**: the explicit restore control calls RevenueCat restore and
70100
re-activates the entitlement for the same store account.
71-
- **Persistence**: entitlement state is re-fetched on launch; after restart the
72-
unlocked state remains correct.
101+
- **Persistence**: entitlement state is re-fetched on launch and the eventual
102+
asynchronous result updates the page; an early synchronous false cannot
103+
remain stuck for the session.
104+
- **Enforcement**: a premium runtime operation rejects an unverified/inactive
105+
claim and accepts a valid active entitlement.
73106
- **Degraded/offline**: RevenueCat errors/no-network default to the free tier;
74107
basic AHBG remains usable.
75108

76109
## hmmm
77110

78111
- Actual project id, product configuration, service-account JSON, and `goog_...`
79112
SDK key require live accounts and cannot be provisioned from this repository.
80-
- The Play sandbox billing verification remains blocked until purchase/restore
81-
controls are implemented in the Android surface.
113+
- The Play sandbox billing verification remains blocked until purchase/restore,
114+
asynchronous entitlement delivery, runtime enforcement, and production
115+
deployment acceptance are implemented.
Lines changed: 59 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# AHBG submission blockers — Google Play (primary)
22

3-
The Android release artifact and entitlement-check boundary are source-ready.
4-
The remaining blockers are split below between repository work and live external
5-
Play/RevenueCat work so a green build is not mistaken for a publishable app.
3+
The Android release artifact is source-buildable, but the billing/acquisition,
4+
entitlement-delivery, runtime-enforcement, and production-deployment boundaries
5+
are not complete. The remaining blockers are split below so a green build is
6+
not mistaken for a publishable or sellable app.
67

78
## 1. Construction (core mechanics) — CLOSED
89

@@ -13,29 +14,50 @@ Play/RevenueCat work so a green build is not mistaken for a publishable app.
1314
- Post-merge hardening is owned by UCNS; AHBG does not invent replacement
1415
construction geometry.
1516

16-
## 2. Billing controls — REPOSITORY BLOCKER
17+
## 2. Billing + entitlement enforcement — REPOSITORY BLOCKERS
1718

18-
RevenueCat initialization and entitlement lookup exist, but the Android/WebView
19-
surface does not yet expose a complete acquisition flow.
19+
RevenueCat initialization and an asynchronous customer-info lookup exist, but
20+
the Android/WebView/runtime path does not yet form a complete premium gate.
2021

2122
- **Blocker**: fetch the current RevenueCat offering/package.
2223
- **Blocker**: launch purchase of `ahbg_benchmark_lab` from a user-visible
2324
control and surface success/cancel/error state.
24-
- **Blocker**: expose an explicit restore control that calls
25-
`Purchases.sharedInstance.restorePurchases` and refreshes entitlement state.
26-
- Regression-test the bridge/API boundary; do not mark the sandbox billing gate
27-
complete from `getCustomerInfo` alone.
28-
29-
## 3. Google Play publication — EXTERNAL (primary path)
30-
31-
- Code compliance is done: `compileSdk`/`targetSdk` 36, AGP 8.9.1, Gradle
32-
8.11.1, Play-native `bundleRelease` in CI, RevenueCat 10.19.1 core, production
33-
HTTPS endpoint, signing config outside Git.
25+
- **Blocker**: expose an explicit restore control using RevenueCat restore.
26+
- **Blocker**: notify/refresh the WebView when asynchronous customer-info refresh
27+
changes `benchmark_lab`; one synchronous read during page startup is not
28+
persistence evidence.
29+
- **Blocker**: carry a server-verifiable entitlement claim to the runtime rather
30+
than trusting a local client Boolean.
31+
- **Blocker**: enforce `benchmark_lab` at the actual premium runtime operations;
32+
a changed status label is not feature gating.
33+
- Regression-test the acquisition, async-refresh, transport, and deny/allow
34+
runtime boundaries before calling the billing gate complete.
35+
36+
## 3. Production AHBG runtime — REPOSITORY/DEPLOYMENT BLOCKER
37+
38+
The Android build carries an intended production `RUNTIME_URL`; that build-time
39+
constant is not proof that the service exists or is healthy.
40+
41+
- **Blocker**: deploy the canonical AHBG runtime at the exact configured HTTPS
42+
URL with valid TLS.
43+
- **Blocker**: verify from a release-equivalent client that `board.html`, session
44+
creation, plan/state calls, entitlement verification, and a premium deny/allow
45+
operation work end to end.
46+
- Preserve the Android layer as transport/presentation only; do not repair a
47+
missing service by embedding a second runtime into the app.
48+
49+
## 4. Google Play publication — EXTERNAL (primary path)
50+
51+
- Code/build compliance is present: `compileSdk`/`targetSdk` 36, AGP 8.9.1,
52+
Gradle 8.11.1, Play-native `bundleRelease` in CI, RevenueCat 10.19.1 core,
53+
and signing config outside Git.
3454
- **Blocker**: Play developer account, app registration, first internal/closed
3555
test release upload, and production promotion.
3656
- **Blocker**: complete Play Console App content requirements: Data safety,
3757
public privacy-policy URL, ads declaration, app-access declaration, target
38-
audience/content declarations, and content-rating questionnaire.
58+
audience/content declarations, content-rating questionnaire, Financial
59+
features declaration, and Health apps declaration. Where AHBG has no
60+
financial/health features, submit the corresponding "none" declaration.
3961
- **Blocker**: create and activate the `ahbg_benchmark_lab` non-consumable
4062
one-time-product purchase option, including price and regional availability.
4163
- **Blocker**: configure the billing-test Google account under Play Console
@@ -45,20 +67,19 @@ surface does not yet expose a complete acquisition flow.
4567
Google currently requires 12 continuously opted-in testers for at least 14
4668
days before production access — start the closed test immediately.
4769

48-
## 4. RevenueCat production provisioning — EXTERNAL
70+
## 5. RevenueCat production provisioning — EXTERNAL
4971

50-
- Client/runtime entitlement-check boundary complete.
5172
- **Blocker**: live RevenueCat project, Google Play app, Google Cloud service
5273
account (Play Developer + Reporting APIs), Play permission grants,
5374
service-account JSON upload, product/entitlement/offering mapping, and the
5475
Google Play app's RevenueCat public SDK key (`goog_...`).
55-
- `rc_...` project identifiers are not valid substitutes for the Android Google
56-
Play public SDK key.
76+
- RevenueCat v2 project IDs use the `proj...` form; project IDs are not valid
77+
substitutes for the Android Google Play public SDK key.
5778
- **hmmm**: RevenueCat/Google Play service-account permissions can take time to
5879
propagate after provisioning.
5980
See `REVENUECAT_PROVISIONING.md`.
6081

61-
## 5. Publish + submission assets — EXTERNAL
82+
## 6. Publish + submission assets — EXTERNAL
6283

6384
- Store listing, privacy policy, demo storyboard, Play runbook, and Devpost
6485
material are in `ahbg/submission/`.
@@ -78,13 +99,22 @@ and follow the archived Galaxy notes.
7899
change; signing needs the production keystore outside Git.
79100
- Connect conforming harness / A0 same contract / build / persist / reload:
80101
verified by `ahbg/runtime` tests and the HTTP bridge.
81-
- Sandbox purchase → `benchmark_lab` unlock → restore → restart persistence:
82-
**BLOCKED** until purchase/restore controls are implemented, then requires
83-
the Play test track, License testing account, active purchase option, and
84-
RevenueCat Play credentials.
102+
- Sandbox purchase → async entitlement refresh → verified runtime unlock →
103+
restore → restart persistence → premium deny/allow: **BLOCKED** until the
104+
repository work in sections 2–3 is implemented, then requires the Play test
105+
track, License testing account, active purchase option, and RevenueCat Play
106+
credentials.
107+
108+
## Smallest repository next action
109+
110+
Add one explicit entitlement-state notification/refresh path from
111+
`RevenueCatPremiumStore` to the WebView and a regression test proving a cold
112+
start can transition from the initial locked state to the eventual RevenueCat
113+
state without restart. This closes one concrete race without pretending that
114+
purchase, restore, server verification, feature gating, or deployment are done.
85115

86116
## hmmm
87117

88-
A buildable AAB is not yet a sellable product. The smallest repository-owned
89-
next step is purchase + restore wiring; the rest of the gate then crosses into
90-
live Play/RevenueCat accounts.
118+
A buildable AAB is not yet a sellable product. After the async entitlement
119+
refresh is repaired, acquisition, verified runtime gating, and production
120+
runtime acceptance remain living continuation before the external store gate.

0 commit comments

Comments
 (0)