diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 5d38745..2aa8294 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -16,7 +16,7 @@ env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' jobs: - assemble-debug: + android-build: runs-on: ubuntu-latest timeout-minutes: 15 steps: @@ -37,3 +37,6 @@ jobs: - name: Assemble debug APK working-directory: mobile/android run: gradle --no-daemon :app:assembleDebug + - name: Build unsigned release AAB + working-directory: mobile/android + run: gradle --no-daemon :app:bundleRelease diff --git a/mobile/android/README.md b/mobile/android/README.md index ffb07f5..8b25e28 100644 --- a/mobile/android/README.md +++ b/mobile/android/README.md @@ -1,13 +1,12 @@ -# SCARED SACRED Android shell +# TIWCG Android shell -This module wraps the existing tested Python game rather than rewriting it. -Chaquopy packages `engine/` and `render/` directly; `mobile_bridge.py` starts -the same table server on `127.0.0.1`, and the Android WebView is only a shell. +This module wraps the existing tested POLITICS / Fifty-Three Days Python game rather than rewriting it. Chaquopy packages `engine/` and `render/` directly; `mobile_bridge.py` starts the same table server on `127.0.0.1`, and the Android WebView is only a shell. + +SCARED SACRED remains Expansion Set 1 inside TIWCG; it is not the Android application identity. ## Store boundary -RevenueCat exists here to satisfy a real product boundary without selling game -power, Witness Accounts, or access to the ruleset. +RevenueCat exists here to satisfy a real product boundary without selling game power, Witness Accounts, or access to the ruleset. - entitlement: `sacred_table` by default - product: configure one Google Play one-time product as **non-consumable** @@ -15,13 +14,15 @@ power, Witness Accounts, or access to the ruleset. - effect: permanent cosmetic Sacred Table skin only - restore: exposed in the native shell -Witness Accounts remain giver-owned, table-bound, and unsellable per base canon. -All playable mechanics remain available without purchase. +Witness Accounts remain giver-owned, table-bound, and unsellable per base canon. All playable mechanics remain available without purchase. -## Build +## Android identity -The build intentionally pins the newest combination currently claimed compatible -by both Android and Chaquopy rather than using incompatible latest versions: +- app label: `TIWCG — POLITICS` +- application ID: `org.theinterdependency.tiwcg` +- first public version: `1.0.0` / version code `1` + +## Build - Android Gradle Plugin 9.2.1 - Gradle 9.4.1 @@ -33,24 +34,24 @@ by both Android and Chaquopy rather than using incompatible latest versions: From `mobile/android`: ```sh -gradle :app:assembleDebug +gradle --no-daemon :app:assembleDebug +gradle --no-daemon :app:bundleRelease ``` The public RevenueCat SDK key is injected at build time and is not committed: ```sh -gradle :app:assembleDebug \ +gradle --no-daemon :app:bundleRelease \ -PREVENUECAT_API_KEY=goog_xxx \ -PREVENUECAT_ENTITLEMENT_ID=sacred_table ``` -With no key, the game still builds and runs; the purchase controls remain -visibly unconfigured rather than pretending monetization works. +With no key, the game still builds and runs; the purchase controls remain visibly unconfigured rather than pretending monetization works. + +## Shipaton handoff -## Store release boundary +See [`SHIPATON.md`](SHIPATON.md) for the exact playable demo path, release gates, Devpost deliverables, store-positioning copy, and two-minute video sequence. -A Shipaton-eligible release still requires the external store configuration: -Google Play app, one-time product, RevenueCat project/offering/entitlement, -signed AAB, store listing, judge access, icon, screenshot, and demo video. +A Shipaton-eligible release still requires external store configuration and publication: Google Play app, one-time product, RevenueCat project/offering/entitlement, signed AAB, store listing, judge access, icon, screenshot, and demo video. hmmm — commerce belongs around the table, not between a witness and the room. diff --git a/mobile/android/SHIPATON.md b/mobile/android/SHIPATON.md new file mode 100644 index 0000000..d7d9a8a --- /dev/null +++ b/mobile/android/SHIPATON.md @@ -0,0 +1,143 @@ +# TIWCG — RevenueCat Shipaton release path + +Status: first-public-release preparation for RevenueCat Shipaton 2026. + +The release slice is deliberately narrow. **POLITICS / Fifty-Three Days is the playable game.** Do not block first publication on the generalized TIWCG turn law, AHBG territory mode, UCNS integration, new knowledge kits, or other planned layers. + +## What ships + +- App: **TIWCG — POLITICS** +- Android application ID: `org.theinterdependency.tiwcg` +- Version: `1.0.0` / version code `1` +- Game: POLITICS / Fifty-Three Days +- Human seat: playable in the Android WebView +- Other seats: current engine-supported agents +- RevenueCat: one permanent cosmetic entitlement +- Entitlement ID: `sacred_table` unless deliberately changed before store creation +- Gameplay, rules, and Witness Accounts are not paywalled + +## Playable demo loop + +The existing game is the Shipaton demo. A judge/player can: + +1. enter the live POLITICS table; +2. observe the Machine reveal a historical beat; +3. inspect the dealt hand, agenda, and Arcanum; +4. lay a static or play an action; +5. discard where required by hand law; +6. use a legal reflex in a reaction window or pass; +7. play the dealt Arcanum; +8. watch the population / E / M state register consequences; +9. continue until the Machine deck empties above population 50 (win) or population reaches 50 or below (loss). + +No separate hackathon-only match should be fabricated. + +## Build gates + +CI must pass both: + +```sh +gradle --no-daemon :app:assembleDebug +gradle --no-daemon :app:bundleRelease +``` + +A real RevenueCat-key build can be produced with: + +```sh +REVENUECAT_API_KEY='goog_...' \ +REVENUECAT_ENTITLEMENT_ID='sacred_table' \ +gradle --no-daemon :app:bundleRelease +``` + +CI intentionally builds an unsigned release AAB. Store upload signing credentials remain external secrets and must not be committed. + +## External release gates + +These cannot be completed by repository code alone: + +- [ ] Create the Android app in Google Play (or another qualifying store) using `org.theinterdependency.tiwcg`. +- [ ] Create the RevenueCat project/app and connect the real store application. +- [ ] Create one one-time, non-consumable cosmetic product. +- [ ] Attach that product to entitlement `sacred_table`. +- [ ] Put the product into the Current Offering. +- [ ] Build/install with the real public RevenueCat Android key. +- [ ] Complete a sandbox/test purchase and restore test. +- [ ] Create and protect the upload-signing key. +- [ ] Sign the release AAB and upload it to the store. +- [ ] Complete store content/privacy/data-safety declarations accurately. +- [ ] Publish the first public version during the Shipaton eligibility window. +- [ ] Provide judge premium access by the method accepted by the Shipaton rules (promo code or qualifying free access mechanism). + +## Store-positioning copy + +### App name + +TIWCG — POLITICS + +### Short description + +A card game where human intervention changes the course of a historical Machine. + +### Core description + +POLITICS is the first playable game inside TIWCG. History advances through an automated Machine deck. Players respond with cards, statics, reactions, Arcana, and coordinated intervention while a population field registers the consequences. + +The game does not ask whether a card sounds persuasive. The engine resolves legal actions and records what changed. Survive the Machine with more than half the population remaining to win. + +The optional Sacred Table purchase changes presentation only. It does not sell stronger cards, rule access, Witness Accounts, or competitive power. + +## Shipaton demo video — maximum two minutes + +Record the real Android build running on the target device. + +Suggested sequence: + +1. **0:00–0:10** — launch `TIWCG — POLITICS`; show the live table. +2. **0:10–0:30** — Machine reveals a beat; show population / E / M and the human hand. +3. **0:30–0:55** — play a real action or static and show the registered change. +4. **0:55–1:15** — show a reaction/reflex window or Arcanum. +5. **1:15–1:35** — show continued Machine/player interleaving and the win/loss objective. +6. **1:35–1:55** — show the RevenueCat Sacred Table purchase/entitlement and resulting cosmetic change. +7. **1:55–2:00** — identify it as the first TIWCG game and end. + +Do not spend the video explaining unimplemented future architecture. Demonstrate what runs. + +## Devpost minimum package + +- [ ] Text description of features/functionality. +- [ ] Public YouTube or Vimeo demo, no longer than two minutes of essential footage. +- [ ] Published Android store URL. +- [ ] 1024×1024 app icon. +- [ ] At least one 1179×2556 screenshot with no device frame. +- [ ] RevenueCat project ID. +- [ ] Android selected as app type. +- [ ] Judge premium-access method. + +Recommended award targets for this release: + +- **Best Game Award** — primary. +- **RevenueCat Peace Prize** — compatible with the game's intervention/repair purpose if the submission describes only implemented behavior and actual intended social benefit. +- **HAMM Award** — only if the monetization explanation is strong enough; the current first-release purchase is intentionally modest and non-pay-to-win. + +## Not release blockers + +The following remain valid TIWCG work, but are not prerequisites for first Shipaton publication: + +- generalized 7-card / draw-2 / drop-2 / METAPAT turn system; +- Base Survival Kit; +- emergent menagerie creation; +- logical-fallacy Instants; +- Paradigm Shift Closure; +- generalized identity coupling; +- UCNS relation adapter; +- first-class generalized EDCM conflict interface beyond current POLITICS behavior; +- AHBG territory mode; +- Discord/social adapters; +- knowledge-kit marketplace; +- user artwork overrides. + +Ship the working game first. Extend the containing system without rewriting the demonstrated match. + +## hmmm + +Store signing, RevenueCat dashboard state, published listing, judge-access code, icon, screenshot, and video are external release artifacts. Repository CI can prove the code builds; it cannot truthfully mark those external gates complete. diff --git a/mobile/android/app/build.gradle.kts b/mobile/android/app/build.gradle.kts index 1fc36c4..e425906 100644 --- a/mobile/android/app/build.gradle.kts +++ b/mobile/android/app/build.gradle.kts @@ -15,15 +15,15 @@ val revenueCatEntitlement = providers.gradleProperty("REVENUECAT_ENTITLEMENT_ID" .getOrElse("sacred_table") android { - namespace = "org.theinterdependency.scaredsacred" + namespace = "org.theinterdependency.tiwcg" compileSdk = 36 defaultConfig { - applicationId = "org.theinterdependency.scaredsacred" + applicationId = "org.theinterdependency.tiwcg" minSdk = 24 targetSdk = 36 versionCode = 1 - versionName = "0.1.0" + versionName = "1.0.0" ndk { abiFilters += listOf("arm64-v8a", "x86_64") diff --git a/mobile/android/app/src/main/AndroidManifest.xml b/mobile/android/app/src/main/AndroidManifest.xml index a8e9e31..5e386fb 100644 --- a/mobile/android/app/src/main/AndroidManifest.xml +++ b/mobile/android/app/src/main/AndroidManifest.xml @@ -5,7 +5,7 @@ diff --git a/mobile/android/app/src/main/java/org/theinterdependency/scaredsacred/MainActivity.java b/mobile/android/app/src/main/java/org/theinterdependency/scaredsacred/MainActivity.java index 6be5044..a418470 100644 --- a/mobile/android/app/src/main/java/org/theinterdependency/scaredsacred/MainActivity.java +++ b/mobile/android/app/src/main/java/org/theinterdependency/scaredsacred/MainActivity.java @@ -1,4 +1,4 @@ -package org.theinterdependency.scaredsacred; +package org.theinterdependency.tiwcg; import android.app.Activity; import android.graphics.Color; @@ -177,14 +177,12 @@ public void onCompleted(StoreTransaction storeTransaction, @Override public void onError(PurchasesError error, boolean userCancelled) { - purchaseButton.setEnabled(!userCancelled && sacredTablePackage != null); if (userCancelled) { purchaseStatus.setText("SACRED TABLE: purchase cancelled"); - purchaseButton.setEnabled(true); } else { purchaseStatus.setText("SACRED TABLE: purchase failed"); - purchaseButton.setEnabled(true); } + purchaseButton.setEnabled(sacredTablePackage != null); } }); }