docs: refresh handoff + populate CHANGELOG [Unreleased] for v0.20
The v0.19.0 handoff had drifted material across seven commits: HEAD pointer was wrong (still claimed 6037596; actually59424a3), "Tags on origin" still claimed v0.19.0 wasn't pushed, the known-flake list still mentioned `pull_failure_sets_error_status` (fixed in67c150b), and three of four v0.19.0 punch-list "candidates" had silently shipped without the doc tracking it. The Android build target landing infb8b2acwasn't mentioned at all despite being the largest single change in the cycle. CHANGELOG [Unreleased] populated with all seven commits grouped into Added / Fixed: Added: - Android build target — first working APK (fb8b2ac) - Android developer setup + build runbook (59424a3) - F3 FPS / frame-time overlay (690e1d2) - "Smart window size" Settings toggle (e1b8766) - "Shareable" badge on Latest-win caption (9b065e5) - Help: M / P / Win-Summary-Enter rows (35516d3) Fixed: - pull_failure_sets_error_status flake (67c150b) SESSION_HANDOFF.md fully rewritten: - Status section reflects HEAD59424a3, clean working tree (apart from this commit's docs), 1170 passing tests, no known flakes - "Where we are" tracks v0.19.0 candidates' close status (3 of 4 shipped, App icon still open and now blocked on a re-export) - New v0.20 candidates table covers all seven commits - New "Phase Android" punch-list section captures the unblocked- by-fb8b2ac work: APK launch verification, dirs::data_dir port, JNI ClipboardManager, Android Keystore, gpgs integration, the cosmetic cargo-apk panic workaround - Process notes call out the async-test starvation pattern (seen twice now), the bin→lib+shim refactor as a reusable pattern, and target-gating-by-default for cross-platform deps - Resume prompt's A–D menu refreshed to reflect actually-open work: APK verification, Phase-Android persistence, app icon, and a v0.20 cut Build: cargo clippy --workspace --all-targets -- -D warnings clean. Tests: 1170 passing / 0 failing. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+138
-113
@@ -1,59 +1,58 @@
|
||||
# Solitaire Quest — Session Handoff
|
||||
|
||||
**Last updated:** 2026-05-06 (post-v0.19.0) — Tagged + pushed at
|
||||
`6037596`. v0.19.0 closes the v0.18.0 punch list (async H-key hint,
|
||||
persistent replay share URLs), expands desktop platform fit (Wayland
|
||||
session support + monitor-aware default window size), polishes the
|
||||
win-celebration and double-click animation paths, and clears two
|
||||
test-flake contributors. A short-lived "Rusty Pixel" pixel-art card
|
||||
theme was prototyped and reverted in the same window.
|
||||
**Last updated:** 2026-05-07 — `[Unreleased]` accumulating v0.20
|
||||
candidates. Seven commits sit on top of v0.19.0: three close items
|
||||
from v0.19.0's punch list (pull-failure flake, smart-window-size
|
||||
opt-out, Shareable badge), one extends Help cheat-sheet coverage,
|
||||
and three open a new performance / portability arc — F3 FPS
|
||||
overlay, Android build target (first working APK), and the matching
|
||||
developer-setup runbook. The Android build is the load-bearing
|
||||
change: `solitaire_app` now compiles into both a desktop `bin` and
|
||||
an Android `cdylib` from the same source.
|
||||
|
||||
## Status at pause
|
||||
|
||||
- **HEAD on origin:** `6037596` (post-tag commit; the tag itself
|
||||
points at this commit).
|
||||
- **HEAD on origin:** `59424a3` (post-Android-runbook commit).
|
||||
- **Working tree:** modified — `CHANGELOG.md` and
|
||||
`SESSION_HANDOFF.md` carry the v0.19.0 promotion + this refresh,
|
||||
ready to commit.
|
||||
`SESSION_HANDOFF.md` carry the v0.20-candidates promotion + this
|
||||
refresh, ready to commit. `artwork/` remains untracked.
|
||||
- **Build:** `cargo clippy --workspace --all-targets -- -D warnings`
|
||||
clean (verified this session).
|
||||
- **Tests:** **1170 passing / 0 failing** across the workspace
|
||||
(verified this session). One known flake remains:
|
||||
`solitaire_engine::sync_plugin::tests::pull_failure_sets_error_status`
|
||||
occasionally fails when cargo-test parallelism starves the
|
||||
`AsyncComputeTaskPool` within the test's 5-update budget. Same
|
||||
shape as the auto-save flake before v0.19.0's hardening; could be
|
||||
fixed similarly with a wall-clock-bounded loop.
|
||||
- **Tags on origin:** `v0.9.0` through `v0.18.0` (v0.19.0 ready to
|
||||
push once committed).
|
||||
(verified this session). The previously-flaky
|
||||
`pull_failure_sets_error_status` is fixed; no known flakes remain.
|
||||
- **Tags on origin:** `v0.9.0` through `v0.19.0`.
|
||||
|
||||
## Where we are
|
||||
|
||||
v0.18.0's resume-prompt menu (A–D) is closed:
|
||||
v0.19.0's "Possible next-round candidates" list shipped 3 of 4:
|
||||
|
||||
- ~~**A — Tag v0.18.0:**~~ shipped at `bfcd05f`.
|
||||
- ~~**B — Solver-on-`AsyncComputeTaskPool` for the H-key hint:**~~
|
||||
shipped at `3e11e9e`.
|
||||
- **C — Desktop packaging:** still gated on artwork + signing
|
||||
certs. Icon export PNGs (11 sizes, 16–1024 px) sit in
|
||||
`artwork/` from the v0.18-era export; not yet wired into the
|
||||
Bevy window or assembled into `.icns` / `.ico`. App icon is
|
||||
the first natural step.
|
||||
- ~~**D — Persistent share link:**~~ shipped at `42d90b1`.
|
||||
- ~~**`pull_failure_sets_error_status` flake fix:**~~ shipped at
|
||||
`67c150b`.
|
||||
- ~~**Settings UI for smart-default-size opt-out:**~~ shipped at
|
||||
`e1b8766`.
|
||||
- ~~**Persistent share link URL on selector caption:**~~ shipped at
|
||||
`9b065e5` (as a "Shareable" badge on the Latest-win caption —
|
||||
the Prev/Next selector chips don't have a live spawn site yet,
|
||||
so the badge attaches to the existing single-replay caption).
|
||||
- **App icon round** — still open. 11 PNGs generated by
|
||||
`artwork/Icon Export.html` are *not* in the `artwork/` directory
|
||||
any more (current `artwork/` holds the reverted Rusty Pixel
|
||||
card PNGs); icon-export needs to be re-run before this item can
|
||||
be picked up.
|
||||
|
||||
The Rusty Pixel theme arc is documented as a sub-history but
|
||||
not part of v0.19.0's content:
|
||||
Two new threads opened that weren't on any prior punch list:
|
||||
|
||||
| Commit | Status |
|
||||
|---|---|
|
||||
| `de47511` PNG-format thumbnail support | reverted |
|
||||
| `17e3112` `pixel_art: bool` field + nearest-sampling opt-in | reverted |
|
||||
| `21ec03b` bundle Rusty Pixel as `embedded://` theme | reverted |
|
||||
| `aad8bb9` / `e41def8` / `0b3140a` reverts | landed |
|
||||
|
||||
The arc remains in commit history for archaeology but the
|
||||
codebase reaches v0.19.0's HEAD identical to where it would be if
|
||||
the arc had never landed.
|
||||
- **F3 FPS / frame-time overlay** (`690e1d2`). `DiagnosticsHudPlugin`
|
||||
wraps `FrameTimeDiagnosticsPlugin`; F3 toggles a top-right
|
||||
readout. Hidden by default; primarily a developer affordance.
|
||||
- **Android build target** (`fb8b2ac` + `59424a3`).
|
||||
`solitaire_app` is now a bin + cdylib hybrid. `cargo apk build`
|
||||
produces a 54 MB APK with full assets. Five gating points
|
||||
resolved (split, manifest, bevy feature, arboard target-gate,
|
||||
keyring target-gate). What's *not* yet verified: APK launch on
|
||||
AVD/phone, `dirs::data_dir()` Android behaviour for the
|
||||
persistence/sync layer.
|
||||
|
||||
### Design direction (unchanged)
|
||||
|
||||
@@ -67,105 +66,131 @@ the arc had never landed.
|
||||
`github.com/funman300/Rusty_Solitaire` is the canonical repo.
|
||||
Always push there.
|
||||
|
||||
## v0.19.0 (2026-05-06)
|
||||
## v0.20 candidates ([Unreleased] in CHANGELOG)
|
||||
|
||||
| Area | Commits | What landed |
|
||||
| Area | Commit | What landed |
|
||||
|---|---|---|
|
||||
| Async H-key hint | `3e11e9e` | New `pending_hint.rs` module: `PendingHintTask` resource, `poll_pending_hint_task` + `drop_pending_hint_on_state_change` systems, cancel-on-replace, stale-state guard via `move_count_at_spawn`. Removes the last synchronous solver hot path. |
|
||||
| Persistent share URLs | `42d90b1` | `Replay.share_url: Option<String>` with `#[serde(default)]`. `poll_replay_upload_result` writes into `replays[0].share_url` + persists. Stats Copy button reads from selected replay. `LastSharedReplayUrl` deleted. |
|
||||
| Auto-save flake fix | `91b7605` | `test_app` clears `PendingRestoredGame(None)` after plugin build; test re-arms the timer in a bounded loop. No production-code change. |
|
||||
| Wayland support | `b57db01` | Adds `wayland` to Bevy features. winit prefers Wayland when `WAYLAND_DISPLAY` is set, falls back to X11. Native Wayland surface instead of XWayland frame. |
|
||||
| Smart default window size | `b57db01` | New `apply_smart_default_window_size` Update system queries `PrimaryMonitor` and resizes the window to ~70 % of monitor's logical size on the first frame. Skipped when saved geometry was applied. |
|
||||
| Win-celebration cleanup | `55c235b` | Drops the duplicate "You Win" toast that rendered behind the WinSummary modal. Cards-fly-off cascade kept; toast removed. |
|
||||
| Double-click reject animation | `d7ffb16` | Single-card double-clicks with no destination now play the same shake + sound as multi-card stack misses. Both priorities' failure paths converge on one `MoveRejectedEvent` write. |
|
||||
| Double-click animation dedup | `6037596` | Drops the redundant `StateChangedEvent` write in `end_drag`'s uncommitted-drag branch; previously raced an in-flight CardAnim and restarted the slide visibly. |
|
||||
| Async-pull flake fix | `67c150b` | `pull_failure_sets_error_status` swaps a fixed 5-update budget for a 5-second wall-clock deadline + `yield_now` between pumps. Closes the last v0.19-era flake. |
|
||||
| Smart window size opt-out | `e1b8766` | New `Settings::disable_smart_default_size: bool` (#[serde(default)]). `solitaire_app::main` reads the flag at startup and skips `apply_smart_default_window_size` registration when set. Settings → Gameplay row toggles it; tooltip notes saved geometry always wins. |
|
||||
| Shareable badge | `9b065e5` | Stats overlay's Latest-win caption gains `\u{2022} Shareable` when the displayed replay carries a `share_url`. Badge appears on the single-replay caption (no Prev/Next live spawn site yet). |
|
||||
| Help: M / P / Win-Summary-Enter | `35516d3` | Three rows added to F1 Help → Overlays. Closes coverage drift on post-v0.18 keys. |
|
||||
| F3 FPS overlay | `690e1d2` | `DiagnosticsHudPlugin` + `FrameTimeDiagnosticsPlugin`. Hidden by default; F3 toggle is not gated by pause/modal state. Smoothed FPS / frame_time. Anchored top-right at `Z_SPLASH + 100`. |
|
||||
| Android first APK | `fb8b2ac` | `solitaire_app` split into bin + lib (cdylib). `[package.metadata.android]` pins SDK 34 / 26. Bevy gains `android-native-activity`. `arboard` and `keyring`/`keyring-core` target-gated to non-Android. 54 MB APK builds; launch on device not yet verified. |
|
||||
| Android runbook | `59424a3` | Debian 13 toolchain install, `cargo apk build` invocation, post-sign panic workaround, wired-vs-stubbed table. Fresh-clone runnable. |
|
||||
|
||||
## Open punch list
|
||||
|
||||
### Carried forward
|
||||
### Carried forward from v0.19.0
|
||||
|
||||
- **Desktop packaging** per `ARCHITECTURE.md §17`. Eleven icon
|
||||
PNG sizes (16, 24, 32, 48, 64, 96, 128, 192, 256, 512, 1024)
|
||||
exported via `artwork/Icon Export.html` sit in `artwork/`
|
||||
pending wiring. Pending: actual Bevy window-icon hookup,
|
||||
macOS `.icns` assembly via `iconutil`, Windows `.ico` via
|
||||
`magick convert`, Linux hicolor PNG hierarchy install,
|
||||
AppImage recipe, macOS notarisation cert, Windows
|
||||
Authenticode cert.
|
||||
- **App icon round.** `Window::icon` not yet wired; no `.icns` /
|
||||
`.ico` / Linux hicolor PNG hierarchy. The 11-size icon export
|
||||
the v0.19 handoff referenced is *not* currently in
|
||||
`artwork/` — re-running `artwork/Icon Export.html` is the
|
||||
prerequisite. Half-day task once the PNGs are back in place.
|
||||
No cert dependency.
|
||||
|
||||
### Possible next-round candidates
|
||||
### New — Phase Android (opened by `fb8b2ac` + `59424a3`)
|
||||
|
||||
- **App icon round** — wire the icon into the Bevy window via
|
||||
`Window::icon`, generate `.icns` and `.ico` from the existing
|
||||
PNGs. Half-day task; doesn't depend on signing certs.
|
||||
- **`pull_failure_sets_error_status` flake fix** — same pattern
|
||||
as the auto-save flake. Wall-clock-bounded loop instead of
|
||||
fixed 5-update budget. ~10 lines.
|
||||
- **Settings UI for "open at this size on launch"** — once the
|
||||
smart-default-size system is shipping, expose a checkbox to
|
||||
*disable* it (player who specifically wants 1280×800 every
|
||||
time). Trivial.
|
||||
- **Persistent share link URL on selector caption** — surface
|
||||
whether the currently-selected replay has a `share_url`
|
||||
populated (e.g. "Replay 3 / 8 \u{2022} Shareable") so players
|
||||
know which entries the Copy button can copy.
|
||||
- **APK launch verification on AVD / device.** `adb install` then
|
||||
`adb logcat` against the bevy_test AVD. Shakes out any
|
||||
Bevy/winit Android-specific runtime bugs not caught by the
|
||||
build alone.
|
||||
- **`dirs::data_dir()` Android port.** Persistence (settings,
|
||||
stats, achievements, replays, progress) all route through this
|
||||
function. Android sandboxing usually demands `getFilesDir()` via
|
||||
JNI. Until verified, the APK may launch but fail to persist
|
||||
anything across cold starts.
|
||||
- **JNI ClipboardManager bridge.** Replaces the Android stub for
|
||||
the Stats "Copy share link" toast. `arboard` doesn't ship an
|
||||
Android backend, so this is a small custom JNI call.
|
||||
- **Android Keystore for credentials.** `keyring` is target-gated
|
||||
to a stub that returns `KeychainUnavailable`; replace with
|
||||
Android Keystore via JNI when sync auth ships on mobile.
|
||||
- **Google Play Games (gpgs) integration.** Listed in `solitaire_gpgs`
|
||||
as a Phase-Android target since Phase 1; now unblocked by the
|
||||
build target.
|
||||
- **Cosmetic `cargo apk build --lib` workaround.** The
|
||||
post-sign panic doesn't affect the APK on disk but produces
|
||||
noisy stderr. Either upstream a cargo-apk fix or document the
|
||||
`--lib` invocation as canonical in the runbook.
|
||||
|
||||
### Other small candidates
|
||||
|
||||
- **Cut v0.20.0** — the seven commits are a coherent bundle (3
|
||||
punch-list closes, 1 docs polish, 1 perf tool, 2 Android arc
|
||||
starters). Tag whenever feels right; the Android arc has more
|
||||
surface to land before it's "done", but the build-works state
|
||||
is a defensible release point.
|
||||
- **Prev/Next selector chips spawn site.** `9b065e5` notes
|
||||
Prev/Next markers exist in `stats_plugin` but no spawn site
|
||||
renders them today — the Shareable badge therefore lands on
|
||||
the single-replay caption. If/when Prev/Next is plumbed to the
|
||||
Stats overlay, the badge will need to follow.
|
||||
|
||||
### Process notes (from this round)
|
||||
|
||||
- **Async port template (worked again):** the H-key port
|
||||
followed `d489e7a`'s `PendingNewGameSeed` shape one-to-one
|
||||
and the second async port required no new infrastructure.
|
||||
Future async ports (e.g. moving `try_solve_with_first_move`'s
|
||||
full-search variant, if it ever surfaces in the picker UI)
|
||||
should follow the same shape.
|
||||
- **Rusty Pixel reverted cleanly:** `git revert` of three
|
||||
contiguous feature commits produced a clean three-revert
|
||||
sequence with no manual conflict resolution. Bisect remains
|
||||
fast over the full v0.19.0 history because the reverts are
|
||||
individual commits, not a squash.
|
||||
- **Defensive event writes pattern:** the
|
||||
`auto_save_writes_after_30_seconds` flake AND the
|
||||
`end_drag` double-animation bug shared a root cause:
|
||||
defensive `MessageWriter` writes that originally covered an
|
||||
edge case which no longer holds, but became load-bearing
|
||||
once another system started paying attention to the event.
|
||||
Worth a periodic pass: any event write that doesn't
|
||||
correspond to a real state change is a candidate for
|
||||
removal.
|
||||
- **Async-test starvation pattern (resolved twice now).**
|
||||
Auto-save flake (v0.19) and pull-failure flake
|
||||
(v0.20-candidates) shared the same root cause: a fixed
|
||||
N-update budget for an `AsyncComputeTaskPool` task to surface
|
||||
its result, which starves under cargo-test parallelism. The
|
||||
wall-clock-bounded loop pattern (`std::thread::yield_now()`
|
||||
between pumps, deadline = `Instant::now() + Duration::from_secs(5)`)
|
||||
is the canonical fix. Future async-test work should reach for
|
||||
this shape on the first commit, not after a flake materialises.
|
||||
- **Bin → lib + thin shim refactor.** The `solitaire_app` split
|
||||
for cargo-apk is a textbook cdylib-as-NativeActivity pattern.
|
||||
Worth knowing as a reusable shape for any future Bevy-on-mobile
|
||||
project: keep `main.rs` to ≤10 lines that delegate to
|
||||
`pub fn run`, put all setup in `lib.rs`, and let the build
|
||||
system pick which artifact (`bin` or `cdylib`) it needs.
|
||||
- **Target-gating defensive defaults.** Three of v0.20-candidates'
|
||||
Android-arc commits had to disable a default-on dependency
|
||||
(`arboard`, `keyring`, `keyring-core`) for the new target.
|
||||
When a future contributor adds a desktop-implicit dependency,
|
||||
reaching for `[target.'cfg(not(target_os = "android"))'.dependencies]`
|
||||
preemptively is cheaper than rediscovering the gating during
|
||||
the next platform port.
|
||||
|
||||
## Resume prompt
|
||||
|
||||
```
|
||||
You are a senior Rust + Bevy developer working on Solitaire Quest.
|
||||
Working directory: <Rusty_Solitaire clone path on this machine>.
|
||||
Branch: master. v0.19.0 just shipped. The next natural item is
|
||||
desktop-packaging follow-through, starting with the app icon.
|
||||
Branch: master. v0.19.0 is tagged on origin; seven commits sit on
|
||||
top opening the v0.20 cycle (3 punch-list closes + a perf tool +
|
||||
the Android build target).
|
||||
|
||||
State: HEAD at 6037596 + the v0.19.0 docs commit on top (this
|
||||
session). Tag v0.19.0 points at the docs commit.
|
||||
State: HEAD at 59424a3 + the v0.20-candidates docs commit on top
|
||||
(this session). Working tree may carry the doc updates if not yet
|
||||
committed.
|
||||
|
||||
READ FIRST (in order, before doing anything):
|
||||
1. SESSION_HANDOFF.md — this file
|
||||
2. CHANGELOG.md — [Unreleased] is empty; [0.19.0] just landed
|
||||
2. CHANGELOG.md — [Unreleased] holds the v0.20 draft
|
||||
3. CLAUDE.md — unified-3.0 rule set
|
||||
4. CLAUDE_SPEC.md — formal architecture spec
|
||||
5. ARCHITECTURE.md — crate responsibilities + data flow
|
||||
6. ~/.claude/projects/<this-project>/memory/MEMORY.md
|
||||
6. docs/android/* — Android setup + build runbook (59424a3)
|
||||
7. ~/.claude/projects/<this-project>/memory/MEMORY.md
|
||||
— saved feedback / project context
|
||||
(machine-local; may be missing on a
|
||||
fresh machine)
|
||||
|
||||
DECISION TO ASK THE PLAYER FIRST:
|
||||
A. App icon — wire artwork/icon-{size}.png into Bevy's
|
||||
Window::icon, generate .icns + .ico, drop into Linux
|
||||
hicolor hierarchy. Half-day task. No cert dependency.
|
||||
B. Desktop packaging continued — AppImage recipe, .desktop
|
||||
file, install scripts. Larger task; unlocks distro
|
||||
packaging. No cert dependency.
|
||||
C. macOS / Windows signing cert acquisition — needs user
|
||||
action; agent can't drive.
|
||||
D. `pull_failure_sets_error_status` flake fix — small, well-
|
||||
scoped. Same pattern as the v0.19.0 auto-save flake fix.
|
||||
A. APK launch verification — `adb install` + `adb logcat` on
|
||||
bevy_test AVD or a physical x86_64 device. Shakes out
|
||||
runtime bugs the build can't catch.
|
||||
B. Phase-Android persistence — port dirs::data_dir() through a
|
||||
JNI getFilesDir() bridge so the APK can survive a cold
|
||||
start. Largest unblocked Android piece.
|
||||
C. App icon — re-run artwork/Icon Export.html, then wire
|
||||
Window::icon + generate .icns / .ico. Half-day task. No
|
||||
cert dependency.
|
||||
D. Cut v0.20.0 — promote [Unreleased] to [0.20.0], tag,
|
||||
push. Mechanical close-out; the Android arc has more
|
||||
surface to land but the build-works state is a defensible
|
||||
release point.
|
||||
|
||||
WORKFLOW NOTES:
|
||||
- Use the system git config (already correct).
|
||||
@@ -173,8 +198,8 @@ WORKFLOW NOTES:
|
||||
"Quat" not "Rhys" (saved feedback memory).
|
||||
- Sub-agents stage + verify only; orchestrator commits.
|
||||
- Every commit must pass build / clippy / test before pushing.
|
||||
- Push to GitHub (origin) — gh auth setup-git is already
|
||||
wired on this machine.
|
||||
- Push to GitHub (origin) — gh auth setup-git wired on
|
||||
primary dev box; verify on laptop before first push.
|
||||
|
||||
OPEN AT THE START: ask which of A–D. Don't pick unilaterally.
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user