diff --git a/CLAUDE.md b/CLAUDE.md index 8c4d71d..03f9ff4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,78 +1,61 @@ -> **Moved to Gitea.** CI now runs on Gitea Actions at -> `git.wallacenet.ca/devadmin/ProLibertateGames`, publishing to Cloudflare Pages -> (`plg.wallacenet.ca`) only. The sandbox notes below describe the earlier GitHub -> setup (no CI run from session pushes, `workflow_dispatch` as the workaround); -> re-verify them against Gitea before relying on them. - # Working on this repo with Claude -## Nothing a session does triggers CI. Dispatch it explicitly. +CI runs on **Gitea Actions** at `git.wallacenet.ca/devadmin/ProLibertateGames` +(workflows in `.github/workflows/`), publishing to Cloudflare Pages +(`plg.wallacenet.ca`). The workflow below was measured on the dev machine +(`~/ProLibertateGames`); it replaces the earlier GitHub-sandbox notes, which no +longer apply. -GitHub creates **no workflow run** for anything this sandbox does — pushing a -branch, opening a pull request, or merging one. All of it goes through the same -integration, and GitHub suppresses event-triggered runs from it. The pull -request will say it was opened by the repo owner; that is only how the UI -attributes it, and it does not change the suppression. +## Build, test and lint locally -This was measured, not assumed: +Gradle works on the dev machine. Two environment variables are required: the +default JDK is 25, which Gradle 8.14 cannot use, and the Android SDK lives in the +home directory. -| Action | Result | -| --- | --- | -| Human pushes a Claude-authored commit (`d165e5ef`, `469c900e`) | CI runs | -| Session pushes `dev` / `main` (`43394b8`, `742add4`) | no run | -| Session opens a PR against `dev` (#1) | no run | -| Session calls `workflow_dispatch` | **runs** | +``` +export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 +export ANDROID_HOME=$HOME/android-sdk # platform 34, build-tools 34.0.0 +./gradlew testDebugUnitTest lintDebug assembleDebug +``` -`workflow_dispatch` works because it creates a run directly instead of relying -on an event. It is the only mechanism available from a session, so every build -has to be asked for by hand. +The Katan tests run in seconds; a clean build takes a few minutes. Run the full +suite, lint and `assembleDebug` before pushing: they are what CI runs. There is +no KVM, so no emulator; the engine and the UI logic are covered by unit tests +(see `docs/UI-catan.md`). -## Verify before merging, without publishing +## Shipping: branch, PR, CI, merge -`ci.yml` builds, tests and lints on any ref, but its staging and publishing -steps are gated on `github.ref == 'refs/heads/dev'`. Dispatching it on a -**feature branch** therefore gives the full check — build, unit tests, Android -lint — and publishes nothing. - -So the working loop is: - -1. Commit and push the feature branch. -2. Dispatch `ci.yml` on that branch. Wait for green. This is the real review - gate, and it is the only verification that exists (see below). -3. Open the PR through the API and merge it there, so the change is reviewable - and the merge commit is honest about what happened. Neither step builds - anything. -4. Dispatch the target branch's workflow to actually build and publish: - `ci.yml` on `dev`, `release.yml` on `main`. - -Skipping step 4 leaves a branch whose head was never built and no release. +1. Branch from `dev`; before pushing, merge `origin/dev` in (it moves between + sessions). +2. Plain `git push` has no credentials. Use the Gitea token as a one-off header: + `git -c "http.extraheader=Authorization: token $(cat ~/.config/gitea/token)" push -u origin `. +3. Open the PR with `POST /api/v1/repos/devadmin/ProLibertateGames/pulls` + (same token, `Authorization: token ...`). CI (`ci.yml`) runs on the PR: build, + unit tests and Android lint; it publishes nothing. Poll + `/actions/runs` until it completes (about 7 minutes). +4. Merge with `POST .../pulls/N/merge {"Do":"merge"}`. The push to `dev` runs + `ci.yml` again and publishes the build (about 9 minutes). ## Merging is a shipping action Both long-lived branches publish, so a merge is a release, not just an integration: -- **`dev`** → `ci.yml` publishes a `v.N-dev` **prerelease**, offered by the - in-app updater to anyone on the Dev channel. -- **`main`** → `release.yml` publishes a **production** release, which the - updater installs for everyone on the Production channel. +- **`dev`** publishes a `v.N-dev` build to + `https://plg.wallacenet.ca/dev/latest.json`, offered by the in-app updater to + anyone on the Dev channel. +- **`main`** runs `release.yml` and publishes a **production** release for + everyone on the Production channel. Confirm before merging to `main`. + `release.yml` runs `assembleDebug` only (no tests, no lint), so a `main` + release is only as verified as the `dev` build it replays. -Confirm before shipping to `main`. Note that `release.yml` runs `assembleDebug` -only — no tests, no lint — so a `main` release is only as verified as the `dev` -build it replays. +## Katan -## Gradle does not run in the sandbox - -`./gradlew` cannot resolve the Android plugin here: the proxy blocks -`dl.google.com` with a 403. No local build, no local test run, no local lint. A -dispatched CI run is the only way to find out whether a change compiles. - -## A permanent fix, if you want one - -The suppression is a property of the sandbox's credential, so it cannot be -fixed from inside a session. Giving the environment a personal access token to -push with would make pushes and PRs behave normally for everyone. Until then, -the dispatch step above is the workaround. +The island game is catalogue id `catan`, shown as **Katan**. It has two rule +sets chosen at setup: the base game (`docs/RULES-catan.md`) and Cities & Knights +(`docs/RULES-catan-ck.md`, code in `game/catan/CatanCk*.kt`, state behind +`CatanState.ck`, which is null in the base game). The screen is layered; see +`docs/UI-catan.md` before changing it. ## Bash output is filtered before it reaches the model