Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
292 changes: 146 additions & 146 deletions .codeyam/dependency-graph.json

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions .codeyam/state/finalize-debt.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"lastFinalizedAt": "2026-07-29T12:50:26Z",
"lastFinalizedSha": "c10509e9f2cec7b9177d65af78384cb5c25b5071",
"lastFullFinalizeSha": "c10509e9f2cec7b9177d65af78384cb5c25b5071",
"lastFullFinalizeTree": "a29f2b2e3ea8a8170d5391b7875c162cb0516baa11e99e8b710f74355a60e032",
"lastFinalizedAt": "2026-07-29T16:00:47Z",
"lastFinalizedSha": "867412a06316387dad9a41c812d9bfc12486f5c1",
"lastFullFinalizeSha": "867412a06316387dad9a41c812d9bfc12486f5c1",
"lastFullFinalizeTree": "475c75c73964da583882770e7cf16858a95257554a4ef8250666794e8c337045",
"deferred": []
}
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
# `--disable-swift-testing` flag used below (absent on older toolchains).
runs-on: macos-15
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Swift version
run: swift --version
Expand All @@ -30,19 +30,19 @@ jobs:
# no emulator is booted — this is compile + JVM unit tests only.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Set up JDK 17
# Gradle 8.7 + Android Gradle Plugin require JDK 17.
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
distribution: temurin
java-version: "17"

- name: Set up Android SDK
# Installs the SDK and accepts licenses, exposing ANDROID_SDK_ROOT so
# Gradle resolves it without the gitignored android/local.properties.
uses: android-actions/setup-android@v3
uses: android-actions/setup-android@v4

- name: Build
run: android/gradlew -p android compileDebugKotlin
Expand Down
71 changes: 71 additions & 0 deletions .github/workflows/codeyam-protection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: codeyam-protection

# codeyam-managed: merge-readiness gates.
#
# `ci.yml` proves the code builds and its tests pass. This workflow proves the
# codeyam state that travels with the code — scenarios, glossary, test registry
# — is actually finalized, which a build/test run cannot see. The two are split
# so a metadata-debt failure is legible on its own rather than reading as a
# broken app.
#
# These are the authoritative backstop for the pre-push hook: a contributor
# pushing from a fork (or with hooks bypassed) is caught here instead.
#
# Recommended: make `Merge-readiness gates` a required status check on `main`
# in repository settings → Branches.

on:
pull_request:
branches: [main]
push:
branches: [main]

jobs:
gates:
name: Merge-readiness gates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
# Every gate walks history: the deferred-finalize check diffs a commit
# range and the full-finalize check resolves a recorded SHA. A shallow
# clone makes both unresolvable.
fetch-depth: 0

- name: Fetch the base branch
# `fetch-depth: 0` gives full history for the checked-out ref, but on a
# pull_request event the `origin/main` remote-tracking ref the
# deferred-finalize gate defaults to may not exist locally. Fetch it
# explicitly so `--base origin/main` always resolves.
run: git fetch --no-tags origin main:refs/remotes/origin/main || true

- name: Set up Node
uses: actions/setup-node@v5
with:
node-version: "20"

- name: Install codeyam-editor
run: npm install -g @codeyam-editor/codeyam-editor@latest

- name: Verify no deferred-finalize commits
# Fails when a commit carries `Codeyam-Finalize: deferred` without a
# later `session-finalize` covering it — i.e. Fast Commit debt that was
# never paid down.
run: |
codeyam-editor editor verify-no-deferred-finalize \
--base origin/main \
--head HEAD \
--format text

- name: Verify a full branch-wide finalize covers HEAD
# The deferred check above only catches *trailered* commits. This one
# catches a branch that simply never ran a full finalize, keeping
# whole-repo debt — invisible to the diff-only Fast Commit gate — off
# `main`.
run: codeyam-editor editor verify-full-finalize --format text

- name: Verify completed plans still have their implementations
# Guards the merge boundary against a post-finalize rebase silently
# dropping the code a plan was archived as "completed" for. Plans with
# no deliverables manifest are reported as needs-review, not failed.
run: codeyam-editor editor verify-completed-plans --format text
9 changes: 5 additions & 4 deletions .github/workflows/play-release.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
name: Play Release

# Manual trigger — build a signed AAB and promote it to a chosen Play track,
# including **production**. The sibling `play-internal.yml` is the zero-argument
# "just get a build to internal testing" button; this one is the parameterized
# including **production**. This is the only Play upload path: the parameterized
# release lever with staged rollout, release notes, and R8 deobfuscation upload.
# It replaced the retired zero-argument `play-internal.yml`; pick the `internal`
# track here for what that button used to do.
#
# Secrets are the SAME five `play-internal.yml` already uses (all configured):
# Secrets are the five the retired workflow used (all configured):
# ANDROID_KEYSTORE_BASE64 / ANDROID_KEYSTORE_PASSWORD /
# ANDROID_KEY_ALIAS / ANDROID_KEY_PASSWORD / PLAY_SERVICE_ACCOUNT_JSON
#
Expand Down Expand Up @@ -58,7 +59,7 @@ jobs:
- uses: actions/checkout@v5

- name: Set up JDK 17
# Gradle 8.4 + AGP require JDK 17 (matches ci.yml and play-internal.yml).
# Gradle 8.4 + AGP require JDK 17 (matches ci.yml).
uses: actions/setup-java@v5
with:
distribution: temurin
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/testflight.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ jobs:
name: Archive & upload to TestFlight
runs-on: macos-26
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5

- name: Show toolchain
run: |
Expand Down
26 changes: 22 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ git clone https://github.com/codeyam-ai/codeyam-counter && cd codeyam-counter
npm install -g @codeyam-editor/codeyam-editor@latest

# Launch the editor (split-screen terminal + live preview)
codeyam-editor editor
codeyam-editor start
```

codeyam-editor requires a subscription to Claude, Gemini, or Codex. Inside the
Expand All @@ -35,7 +35,7 @@ you're changing.

- **iOS** — macOS with a recent Xcode (Swift 6 toolchain) and an iOS 15+
simulator or device.
- **Android** — JDK 17 plus the Android SDK (compile SDK 34), and an emulator
- **Android** — JDK 17 plus the Android SDK (compile SDK 35), and an emulator
image for the preview. See [ANDROID_SETUP.md](ANDROID_SETUP.md).

## Building and testing by hand — iOS
Expand Down Expand Up @@ -73,9 +73,26 @@ build and test commands are:
```bash
android/gradlew -p android compileDebugKotlin
android/gradlew -p android testDebugUnitTest

# Verify the committed Compose snapshots still match
android/gradlew -p android verifyPaparazziDebug
```

[Paparazzi](https://github.com/cashapp/paparazzi) renders the Compose components
off-device on the JVM, so the goldens under
`android/app/src/test/snapshots/` are checked without an emulator. **CI runs
`verifyPaparazziDebug` too**, so a change to a component's rendering fails there
unless you re-record and commit the new goldens:

```bash
android/gradlew -p android recordPaparazziDebug
```

CI runs these same two commands on Ubuntu with JDK 17. Put JVM unit tests under
Review the resulting image diff before committing it — a re-record makes the
check pass by definition, so it is only correct when the visual change is
intended.

CI runs these same commands on Ubuntu with JDK 17. Put JVM unit tests under
`android/app/src/test/` and register them with the editor
(`codeyam-editor editor reconcile-registry --auto-apply`) so they stay tracked
alongside the scenarios, exactly as on the iOS side.
Expand All @@ -87,7 +104,8 @@ alongside the scenarios, exactly as on the iOS side.
captured and registered as you go.
3. Ensure the build and tests pass for the platform(s) you touched — the iOS
`swift build`/`swift test` commands and/or the Android
`compileDebugKotlin`/`testDebugUnitTest` commands above. CI runs both.
`compileDebugKotlin`/`testDebugUnitTest`/`verifyPaparazziDebug` commands
above. CI runs both platforms.
4. Open a PR describing what changed and why, and fill in the PR template.

## Code of conduct
Expand Down
32 changes: 16 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ git clone https://github.com/codeyam-ai/codeyam-counter && cd codeyam-counter
npm install -g @codeyam-editor/codeyam-editor@latest

# Launch the editor (split-screen terminal + live preview)
codeyam-editor editor
codeyam-editor start
```
<!-- codeyam:run-and-edit:end -->

Expand Down Expand Up @@ -61,7 +61,7 @@ device. See [IOS_SETUP.md](IOS_SETUP.md) for simulator prerequisites.
### Android

A native Kotlin + Jetpack Compose port lives in [`android/`](android/). Requires
JDK 17 and the Android SDK (compile SDK 34).
JDK 17 and the Android SDK (compile SDK 35).

```bash
# Compile the sources and run the JVM unit tests
Expand All @@ -85,33 +85,33 @@ States captured as runnable scenarios with codeyam-editor:

<img src=".codeyam/scenarios/screenshots/android-counter-active-count--phone-portrait.png" alt="Android Counter - Active count" width="280">

### Android Counter - Added blank slot selected
### Counter - Active count

<img src=".codeyam/scenarios/screenshots/android-counter-added-blank-slot-selected--phone-portrait.png" alt="Android Counter - Added blank slot selected" width="280">
<img src=".codeyam/scenarios/screenshots/counter-active-count--iphone-16.png" alt="Counter - Active count" width="280">

### Android Counter - All but one deleted
### Android Counter - Added blank slot selected

<img src=".codeyam/scenarios/screenshots/android-counter-all-but-one-deleted--phone-portrait.png" alt="Android Counter - All but one deleted" width="280">
<img src=".codeyam/scenarios/screenshots/android-counter-added-blank-slot-selected--phone-portrait.png" alt="Android Counter - Added blank slot selected" width="280">

### Android Counter - All counters list
### Counter - Added blank slot selected

<img src=".codeyam/scenarios/screenshots/android-counter-all-counters-list--phone-portrait.png" alt="Android Counter - All counters list" width="280">
<img src=".codeyam/scenarios/screenshots/counter-added-blank-slot-selected--iphone-16.png" alt="Counter - Added blank slot selected" width="280">

### Android Counter - All counters list with blank slot
### Android Counter - All but one deleted

<img src=".codeyam/scenarios/screenshots/android-counter-all-counters-list-with-blank-slot--phone-portrait.png" alt="Android Counter - All counters list with blank slot" width="280">
<img src=".codeyam/scenarios/screenshots/android-counter-all-but-one-deleted--phone-portrait.png" alt="Android Counter - All but one deleted" width="280">

### Android Counter - App Settings open
### Counter - All but one deleted

<img src=".codeyam/scenarios/screenshots/android-counter-app-settings-open--phone-portrait.png" alt="Android Counter - App Settings open" width="280">
<img src=".codeyam/scenarios/screenshots/counter-all-but-one-deleted--iphone-16.png" alt="Counter - All but one deleted" width="280">

### Android Counter - App Settings sound and haptic on
### Android Counter - All counters list

<img src=".codeyam/scenarios/screenshots/android-counter-app-settings-sound-and-haptic-on--phone-portrait.png" alt="Android Counter - App Settings sound and haptic on" width="280">
<img src=".codeyam/scenarios/screenshots/android-counter-all-counters-list--phone-portrait.png" alt="Android Counter - All counters list" width="280">

### Android Counter - Blank slot incremented
### Counter - All counters list

<img src=".codeyam/scenarios/screenshots/android-counter-blank-slot-incremented--phone-portrait.png" alt="Android Counter - Blank slot incremented" width="280">
<img src=".codeyam/scenarios/screenshots/counter-all-counters-list--iphone-16.png" alt="Counter - All counters list" width="280">
<!-- codeyam:scenario-gallery:end -->

## Contributing
Expand Down
12 changes: 8 additions & 4 deletions store/playstore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ These are decisions, not bugs. Do not "fix" them.
- **`versionCode` must increase on every single upload**, including a re-upload
to the same track, and can never be reused. This is the most common cause of a
rejected Play upload. Local builds default to `1`; CI passes
`-PversionCodeOverride=<n>` (see `.github/workflows/play-internal.yml`).
`-PversionCodeOverride=<n>` (see `.github/workflows/play-release.yml`).
- **Upload key** lives at `android/app/upload-keystore.jks` (git-ignored), with
credentials in `android/keystore.properties` (git-ignored) or the
`ANDROID_KEYSTORE_*` env vars. **Play App Signing** is enrolled, so this is
Expand All @@ -128,13 +128,17 @@ These are decisions, not bugs. Do not "fix" them.

- Fill the Play Console store listing from `listing.md` and upload the graphics
above.
- Clear the App content declarations using `PLAY_CONSOLE_CHEATSHEET.md`.
- Clear the App content declarations using
[PLAY_CONSOLE_CHEATSHEET.md](PLAY_CONSOLE_CHEATSHEET.md).
- **Closed testing gate:** a recently-created *personal* developer account must
run a closed test with **≥12 testers for 14 continuous days** before
production access is unlocked. This does not affect Internal testing. Confirm
which account type applies before committing to a launch date.
- Optionally upload the R8 deobfuscation mapping file
(`android/app/build/outputs/mapping/release/mapping.txt`) so Play can
symbolicate release crash reports.
- The privacy policy page mentions iCloud backups; consider making that line
OS-neutral (Android uses Google Auto Backup) for a public launch.

The privacy policy at `https://codeyam.com/counter/privacy` is already
OS-neutral — the backup clause names both Apple and Google, so it reads
correctly for an Android reviewer. The page lives in `codeyam-ai/codeyam`
(`dashboard/app/routes/counter.privacy.tsx`), not this repo.