The bootstrap rebranded the app to Pilgrims of Katan (WALA-118 review);
the decision is to keep the upstream's own identity instead.
- Title and splash: the upstream originals restored exactly — the Wallace
tartan splash under the "Pro Libertate Games" uncial wordmark
(SplashScreen.kt, Tartan.kt), the tartan launcher icon, and the
Theme.ProLibertateGames window theme. The game screens go back to the
upstream WallaceGold/WallaceRed accents the tartan is woven from.
- Names and colours: launcher names back to "Pro Libertate Games" /
"Pro Libertate Games DEV"; the channel colours back to the clan red /
hunting green setts (resValue tartan_field and friends). The installed
identity stays ca.wallacenet.pilgrimsofkatan (+ .dev) — that is the
package, not the brand.
- Catalogue: Katan is listed under Board Games (3-4 players, original
blurb, no third-party marks) with available = false, so dev builds show
it as "Coming soon" and a production build hides it until its engine
and screen land.
- Docs: README/CLAUDE.md/docs/CI.md updated to the restored identity;
CatalogTest's invariant now names Katan as the one deliberate exception
rather than asserting nothing is unfinished.
Structural bootstrap untouched: applicationId, OTA repointed at the Gitea
releases, CI workflows, version stamping.
Verified: ./gradlew assembleDebug and testDebugUnitTest green — 628 tests,
0 failures.
Co-Authored-By: Paperclip <[email protected]>
Import of ProLibertateGames (upstream main, GPL-3.0) rebranded for
Wallacenet and repointed at git.wallacenet.ca.
- Identity: applicationId ca.wallacenet.pilgrimsofkatan (+ .dev for the dev
channel), launcher names "Pilgrims of Katan" / "Pilgrims of Katan DEV",
neutral hexagon branding replacing the Wallace tartan. Uncial Antiqua keeps
its OFL licence, and the GPL-3.0 LICENSE plus upstream attribution stay.
- OTA: Updater.kt now reads this repo's own Gitea releases
(/api/v1/repos/devadmin/PilgrimsOfKatan/releases...) and BuildConfig.
OTA_ENABLED is on; Gitea answers the same JSON shape the code already parsed.
- Build numbers: versionCode = CI run number + plgVersionRunOffset (1000),
with the tag and versionName derived from the same figure. The offset is
permanent, because Gitea Actions restarts run numbers at 1 and a reset would
otherwise make Android reject the next build as a downgrade.
- CI: ci.yml publishes a dev prerelease from dev, release.yml a production
release from main, both through scripts/publish-release.sh (Gitea REST API,
runnable by hand until an Actions runner is registered).
- Docs: docs/CI.md records the channel, numbering and runner decisions;
docs/README.md seeds the per-game RULES-* conventions; CLAUDE.md carries the
agent ground rules.
Verified: ./gradlew assembleDebug and testDebugUnitTest green on JDK 17 /
compileSdk 34, both variants stamped, installing side by side under the new
identity.
Co-Authored-By: Paperclip <[email protected]>
The series a build is named for was written out three times — in the
build file and in both workflows' tag lines — so bumping it meant
changing all three and a release could be tagged one thing and built as
another. It now lives in gradle.properties as plgVersionSeries, which
the build reads when it stamps the APK and both workflows read when they
name the tag.
Set to 1.1.
versionCode is deliberately left as the CI run number alone, which is
what makes the bump safe: the run number keeps climbing across a change
of series, so 1.1 never looks like a downgrade to Android and an OTA
update is not interrupted. The series is a name for people; the run
number is what the machines compare. The updater already read only the
trailing number, and its comments now say so rather than naming 1.0.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_019Pr6B8xDDtJJcb6WJMw7Ud
A dev build now installs under its own applicationId, org.prolibertate.games.dev,
so it is a separate app to Android and sits beside the production copy instead
of replacing it. Each channel still updates itself normally, because an update
within a channel keeps the same package.
Three things move together off one isDevBuild flag, because a dev package
wearing the production name and colours is exactly the mix-up that having both
installed is meant to prevent:
- applicationId gets a .dev suffix;
- the launcher label becomes "Pro Libertate Games DEV";
- the cloth becomes Wallace Hunting, the same threadcount with green where
the clan sett has red.
The name and the colours reach the resources through resValue, so app_name,
tartan_field, splash_background and ic_launcher_background are generated by the
build rather than declared in res/values. The icon vectors reference
@color/tartan_field instead of a literal, which is how one set of vectors serves
both colourways without a second copy of the paths. BuildConfig.DEV_BUILD
carries the same flag into Kotlin, where AppSett picks the Compose sett for the
splash, and WallaceHuntingSett is derived from the same threadcount builder as
WallaceSett so the two cannot drift.
versionName now tracks isDevBuild rather than the CI stamp alone, so an
unstamped local build cannot claim a channel its applicationId contradicts.
Separate packages also mean a channel switch can no longer be refused as a
downgrade; the settings copy and the README said it could, and now say what
actually happens.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JDuAayWXLRoUNTsfE79Mg1
Multiplayer now runs over Wi-Fi (LAN) only.
- Delete BluetoothTransport and drop it from LobbyController's transport
list, leaving LanTransport as the sole transport.
- Drop TransportKind.BLUETOOTH and the now-unused RFCOMM_UUID constant.
- Remove the BLUETOOTH/BLUETOOTH_ADMIN/BLUETOOTH_CONNECT permissions and
the android.hardware.bluetooth feature from the manifest, along with
the runtime permission request in MainActivity and the
requestBluetoothPermissions hook on AppEnv.
- Update lobby copy so an empty transport list and an empty host list
talk about Wi-Fi rather than pairing, and refresh the comments and
README sections that described two transports.
The transport abstraction itself is kept: everything after the handshake
was already transport independent, so adding another one later needs no
changes above LanTransport.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01YEsqYAMJKUJoM7UAavm169
Update channels
- ci.yml now publishes each green push to dev as a prerelease tagged
v1.0.<n>-dev, so the dev channel has something to install. Workflow
artifacts could not serve this: downloading one needs authentication,
which the app does not have.
- Prereleases specifically, because GitHub's "latest release" endpoint
skips them — a production install can never be handed a dev build.
Pull requests build and check but never publish.
- Settings gains a channel picker. The two channels are numbered by
separate workflow run counters, so versions are only compared within a
channel; the app reads the -dev suffix in its own versionName to know
where it stands, and treats a channel change as an explicit switch. The
screen warns that such a switch can be a downgrade Android will refuse.
- PLG_RELEASE becomes PLG_CHANNEL, naming the channel rather than a flag.
Euchre
- Cards in a trick now sit on the side of the table belonging to whoever
played them, rotated to face them, labelled You / Left / Partner /
Right. Previously they were a flat row tagged with seat numbers, which
made it hard to tell who had played what.
- Bidding says what it will actually do. As dealer the button reads "Pick
it up" rather than "Order up", since the turn card comes to your hand,
and a line of explanatory text spells out the consequence either way.
Sequence
- Playable squares get a much heavier outline, scaled off cell size and
in a fixed amber that reads against a white card, a green corner and a
chip alike. The old 2dp theme-coloured border was hard to see.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN
Two ways the updater could have served or blocked the wrong build:
- release.yml also triggers on workflow_dispatch, which can be aimed at
any branch from the Actions UI. That would have built dev code and
published it as a real Release, which every install would then offer to
download. The job now refuses to run off anything but main.
- versionCode came from GITHUB_RUN_NUMBER, but that counter is per
workflow, so the dev pipeline had its own independent sequence. A debug
APK installed from a CI artifact already carried a higher versionCode
than the first several releases would, and the updater's check is
latest <= installed, so those users would have been told they were up
to date indefinitely. Only release.yml now sets PLG_RELEASE, and only
that stamps a real version; everything else stays at 1.0.0-dev.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN
First vertical slice: the whole shell plus two games playable end to end,
so every layer is exercised before the other nine games are built on it.
Games
- Euchre: bowers, ordering up, dealer discard, going alone, stick the
dealer, and full scoring. Rule variants (deck size, points to win,
stick the dealer, going alone) are toggles in game setup.
- Sequence: two-eyed and one-eyed jacks, free corners, locked sequences,
the shared-chip limit, and dead-card exchange. Teams, players per team
and the sequence target are toggles.
- The board layout in SequenceBoard is generated, not the commercial
board — it holds every structural property the rules need, but does not
match a physical board. Documented in docs/RULES-sequence.md.
Multiplayer
- One transport abstraction over newline-delimited JSON, implemented
twice: LAN via NSD discovery and TCP, Bluetooth via Classic RFCOMM.
A lobby advertises on both at once, so a table can mix them.
- Host-authoritative: clients send move intents, the host re-validates
every one against the rules, and each client receives a state redacted
for its own seat so hidden information never crosses the wire.
- Seats start as AI and are handed to people as they join, which is what
makes any mix of humans and AI work without a separate code path.
Shell
- Main menu lists all eleven games; the nine without engines are marked
coming soon and are driven entirely by GameCatalog.
- Settings: sound, animation speed (one multiplier drives card movement
and AI thinking time), and OTA updates from the latest GitHub release.
- Layouts measure available space rather than assuming an orientation.
The game package is free of Android types, so the rules engines and AI
run under plain JUnit; 43 tests cover ranking, following suit, scoring,
sequence detection, redaction, wire round-trips and full random and AI
playthroughs.
Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_015qjfMiPUDshdKEUa6vxqzN