docs: cut v0.20.0 — Terminal design system + Android persistence

Promotes the [Unreleased] section to [0.20.0] dated 2026-05-07
and opens a fresh empty [Unreleased]. The cycle's two through-
lines:

- **Terminal visual-identity port.** ui_theme token system
  (0d477ac) is load-bearing; downstream chrome migrations cover
  the modal scaffold, gameplay-feedback layer (ceec4fc), toasts
  with a new ToastVariant enum (a137607), table chrome (651f406),
  card chrome (d752870), splash cursor (cdcadda), and final
  hint-source / dest pairing (9891ae4). Card-face / suit / card-
  back palette intentionally NOT migrated — those track PNG
  artwork that hasn't been regenerated yet. The 24 Stitch-rendered
  mockups and design-system.md spec landed in fa7f98a.
- **Android persistence shim.** solitaire_data::data_dir
  routes through a per-platform shim (4b51e50) closing the
  CLAUDE.md §10 dirs::data_dir() = None pitfall on Android.
  Settings, stats, achievements, replays, game-state, time-attack
  sessions, and user themes now persist on a real APK.

Also closes three v0.19.0 punch-list candidates that landed
earlier in the cycle (pull_failure flake at 67c150b, smart-window-
size opt-out at e1b8766, Shareable badge at 9b065e5).

Tests: 1176 passing / 0 failing (six new this cycle: ui_theme
invariant guards, toast-variant-border-mapping, palette-tracking
guards on MARKER_VALID / HINT_PILE_HIGHLIGHT_COLOUR /
RIGHT_CLICK_HIGHLIGHT_COLOUR / toast-border distinctness).

SESSION_HANDOFF.md refreshed: HEAD pointer, test count, the
v0.20.0 changelog summary, the open punch list (Phase Android
runtime gaps, visual-identity follow-ups including the artwork
regeneration item), the updated design-direction box (was
Midnight Purple + Balatro yellow; now base16-eighties Terminal),
and a refreshed Resume Prompt offering A–F next-step options.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-07 18:58:51 -07:00
parent fa7f98ac52
commit 41a009a693
2 changed files with 383 additions and 164 deletions
+230 -153
View File
@@ -1,196 +1,273 @@
# Solitaire Quest — Session Handoff
**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.
**Last updated:** 2026-05-07 — v0.20.0 cut. Two through-lines closed
in this cycle: a full **Terminal visual-identity port** (token system
in `ui_theme` plus downstream chrome migrations across modal scaffold,
gameplay-feedback, toasts, and the table / card / splash surfaces)
and the **Android persistence shim** that closes the
`dirs::data_dir() = None` pitfall flagged in CLAUDE.md §10. The
Android *build* target landed earlier in the cycle (`fb8b2ac`); this
session paid down the persistence half so a real APK can survive a
cold start. The 24 Stitch-rendered mockups are now in-tree under
`docs/ui-mockups/`; future plugin work diffs against the matching
mockup before touching pixels.
## Status at pause
- **HEAD on origin:** `59424a3` (post-Android-runbook commit).
- **Working tree:** modified — `CHANGELOG.md` and
`SESSION_HANDOFF.md` carry the v0.20-candidates promotion + this
refresh, ready to commit. `artwork/` remains untracked.
- **HEAD on origin:** the v0.20.0 docs commit (the one that lands
this file + CHANGELOG cut). Tag not yet pushed; cut whenever
feels right.
- **Working tree:** clean apart from the still-untracked `artwork/`
directory (intentional — the card PNGs there are mid-flight for
the Terminal aesthetic and committing now would freeze a
transitional state).
- **Build:** `cargo clippy --workspace --all-targets -- -D warnings`
clean (verified this session).
- **Tests:** **1170 passing / 0 failing** across the workspace
(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`.
clean.
- **Tests:** **1176 passing / 0 failing** across the workspace.
Six new tests this cycle: four `ui_theme` invariant guards
(type / spacing / z-index scales + `scaled_duration`), one
toast-variant-border-mapping pair, and four palette-tracking
guards on `MARKER_VALID` / `HINT_PILE_HIGHLIGHT_COLOUR` /
`RIGHT_CLICK_HIGHLIGHT_COLOUR` / toast-border distinctness. No
known flakes.
- **Tags on origin:** `v0.9.0` through `v0.19.0`. v0.20.0 not yet
tagged.
## Where we are
## What shipped in v0.20.0
v0.19.0's "Possible next-round candidates" list shipped 3 of 4:
### Terminal visual-identity port
- ~~**`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.
Top-down stack — every commit downstream of the token system
reads from it, so swapping the palette is now a one-file edit:
Two new threads opened that weren't on any prior punch list:
- **`ui_theme` token system** (`0d477ac`). base16-eighties
palette, 5-rung type scale, 7-rung 4-multiple spacing scale,
3-step radius, 14-rung z-index hierarchy, full motion budget,
4 invariant-pinning unit tests. Card-shadow alphas pinned to 0
(Terminal achieves depth via 1px borders + tonal layering).
- **Modal scaffold already on tokens** — `ui_modal` was ported
in the same commit's wake; three stale "loud yellow" /
"magenta secondary" doc comments fixed.
- **Gameplay feedback → semantic state tokens** (`ceec4fc`).
Selection / valid-drop tints route through `ACCENT_PRIMARY` /
`STATE_WARNING` / `STATE_SUCCESS`.
- **Toasts** (`a137607`). New `ToastVariant` enum
(Info / Warning / Error / Celebration); opaque `BG_ELEVATED`
+ 1px accent border + bottom-anchor. All ten call sites pass
their semantic variant.
- **`table_plugin` chrome** (`651f406`).
`PILE_MARKER_DEFAULT_COLOUR` promoted; `cursor_plugin` imports
it, replacing a "kept in sync" doc comment with a compile-
enforced invariant. `HINT_PILE_HIGHLIGHT_COLOUR`
`STATE_WARNING`.
- **`card_plugin` chrome** (`d752870`). Drag-elevation shadow
routes through `CARD_SHADOW_*` tokens. `RIGHT_CLICK_HIGHLIGHT_COLOUR`
`STATE_SUCCESS`. Stock recycle "↺" text → `TEXT_PRIMARY @ 0.7α`.
Card-face / suit / card-back palette intentionally NOT migrated
(artwork dependency — see open-list item below).
- **Splash cursor** (`cdcadda`). The signature `▌` cyan glyph
(96 px) added above the wordmark, matching the spec.
- **Hint-source / dest pairing** (`9891ae4`). `input_plugin`'s
source-card tint now matches the destination pile's
`STATE_WARNING`.
- **Design system + 24-mockup library** (`fa7f98a`).
`docs/ui-mockups/design-system.md` + 24 Stitch mockups (HTML +
PNG) covering every screen plus 9 missing-plugin surfaces.
- **`card_shadow_params` test aligned** (`1d1543e`). Drag-vs-
idle shadow assertion loosened to `>=` to accept the Terminal
"no shadow" intent without losing the regression-guard.
- **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.
### Android persistence
### Design direction (unchanged)
- **`solitaire_data::data_dir` shim** (`4b51e50`). New
`solitaire_data::platform::data_dir()` falls through to
`dirs::data_dir()` on desktop and returns the per-app sandbox
at `/data/data/com.solitairequest.app/files` on Android — no
JNI needed (package id pinned in `[package.metadata.android]`).
Six `solitaire_data` callsites + `solitaire_engine/assets/user_dir.rs`
migrated. Settings, stats, achievements, replays, game-state,
time-attack sessions, and user themes now persist on Android.
- **Tone:** Balatro — chunky readable type, theatrical hierarchy,
satisfying micro-interactions.
- **Palette:** Midnight Purple base + Balatro yellow primary + warm
magenta secondary.
### Inherited from earlier in the cycle (pre-session)
- Android build target + APK (`fb8b2ac`), runbook (`59424a3`),
F3 FPS overlay (`690e1d2`), Smart Window Size opt-out
(`e1b8766`), Shareable badge (`9b065e5`), Help cheat-sheet
M/P/Enter rows (`35516d3`), `pull_failure_sets_error_status`
flake fix (`67c150b`).
## Open punch list
### Phase Android (build + persistence shipped; runtime gaps remain)
- **APK launch verification on AVD / device.** `adb install` then
`adb logcat` against the `bevy_test` AVD or an x86_64 device.
The build works and persistence is wired, but no end-to-end
device run has been logged. Shakes out runtime bugs the build +
unit tests can't catch.
- **JNI ClipboardManager bridge.** Replaces the Android stub for
the Stats "Copy share link" toast. `arboard` doesn't ship an
Android backend; small custom JNI call.
- **Android Keystore for credentials.** `keyring` is target-gated
to a stub returning `KeychainUnavailable`; replace with Android
Keystore via JNI when sync auth ships on mobile.
- **Google Play Games (gpgs) integration.** Listed as a
Phase-Android target since Phase 1; now unblocked by the build
target.
- **Cosmetic `cargo apk build --lib` workaround.** Post-sign
panic doesn't affect the APK on disk but produces noisy stderr.
Either upstream a cargo-apk fix or document `--lib` as
canonical in the runbook.
### Visual-identity follow-ups (opened by v0.20.0's port)
- **Card-face / suit / card-back artwork regeneration.** The
Terminal spec calls for dark `#1a1a1a` cards with light suit
pips (pink for hearts/diamonds, foreground gray for spades/
clubs); the runtime path still renders the legacy white-card
PNG artwork. The fallback constants in `card_plugin`
(`CARD_FACE_COLOUR`, `RED_SUIT_COLOUR`, `BLACK_SUIT_COLOUR`,
`CARD_FACE_COLOUR_RED_CBM`, `card_back_colour` palette) are
intentionally unmigrated and should swap in lockstep with the
artwork. Largest visible payoff remaining in the visual-
identity arc.
- **Splash boot-loader richness.** The mockup
(`docs/ui-mockups/splash-mobile.html`) calls for a scanline
overlay, ✓ lime check log lines, pulsing cursor, ROOT@SOLITAIRE
prompt, and a loading bar — none of which v0.20.0's
cursor-glyph-only port pulled in. Aesthetic feature, its own
commit.
- **Replay-overlay redesign.** The mockup
(`docs/ui-mockups/replay-overlay-mobile.html`) envisions a
much richer surface (terminal `▌replay.tsx` header, move log
scroll, MOVE 47/87 chip, WIN MOVE callout, status bar) versus
the current top banner. Aesthetic feature.
- **Toast Warning / Error variants.** The new `ToastVariant`
enum has slots for `Warning` (gold) and `Error` (pink) but no
in-engine event uses them yet (the four current toast events
all map to Info or Celebration). Wire when a warning- or
error-flavoured toast event materialises.
### Carried forward from v0.19.0
- **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/` (current `artwork/` holds the reverted Rusty
Pixel card PNGs and is intentionally untracked); icon-export
needs to be re-run before this item can be picked up.
Half-day task once the PNGs are back in place. No cert
dependency.
### Other small candidates
- **Prev/Next selector chips spawn site.** v0.19.0's `9b065e5`
noted 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,
the badge will need to follow.
- **Toast queue / immediate unification.** The two toast paths
(`spawn_queued_toast` for `InfoToastEvent` queue; `spawn_toast`
for fire-and-forget) now share visual treatment but remain
separate functions because they serve different temporal
needs (sequential vs. parallel). If overlap becomes a UX
issue, merge into one queue with priority lanes.
### Process notes
- **Token-port pattern.** v0.20.0's chrome-migration commits
set a reusable shape for "centralized design system applied
across N plugins":
1. Constants module (`ui_theme.rs`) is the source of truth.
2. Const sites that can't call `Alpha::with_alpha` (not yet
`const` on stable) use a literal RGB matching the token,
with a unit test pinning the RGB to the token (e.g.
`MARKER_VALID`, `HINT_PILE_HIGHLIGHT_COLOUR`,
`RIGHT_CLICK_HIGHLIGHT_COLOUR`).
3. Cross-plugin duplication (e.g. `MARKER_DEFAULT`
`PILE_MARKER_DEFAULT_COLOUR`) collapses to a single
promoted const re-exported from one plugin and imported
by the other — replaces "kept in sync" doc comments with a
compile-time invariant.
4. Domain colours (suit pips, card faces, lerp helpers) stay
as literals with a comment naming the rationale; only UI
chrome routes through tokens.
- **Audit before migrating wide.** Before touching any plugin,
grep for the literal pattern (`Color::srgb\(|Color::srgba\(|
Color::WHITE|Color::BLACK`) and classify each hit as domain
vs. chrome. Most plugins after the modal scaffold port turned
out to be 100 % token-correct already; the audit prevents
wasted churn.
### Canonical remote
`github.com/funman300/Rusty_Solitaire` is the canonical repo.
Always push there.
## v0.20 candidates ([Unreleased] in CHANGELOG)
### Design direction (now Terminal — base16-eighties)
| Area | Commit | What landed |
|---|---|---|
| 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. |
- **Tone:** retro-terminal / synthwave — flat depth (no box-shadows),
monospaced-forward typography (JetBrains Mono / FiraMono), tight
16 px edge margins, 8 px card radius.
- **Palette:** near-black surface ramp (`#151515` / `#202020` / `#2a2a2a`
/ `#353535`), cyan primary CTA (`#6fc2ef`), lime success
(`#acc267`), gold warning (`#ddb26f`), pink error / suit-red
(`#fb9fb1`), lavender celebration (`#e1a3ee`), teal info
(`#12cfc0`).
- **Two-color suits.** Red = `#fb9fb1`, black = `#d0d0d0`. Outlined
glyphs for diamonds & clubs are *always on*; the Settings
"color-blind mode" toggle only swaps red → cyan.
## Open punch list
### Carried forward from v0.19.0
- **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.
### New — Phase Android (opened by `fb8b2ac` + `59424a3`)
- **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-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.
(Was: Midnight Purple base + Balatro yellow primary + warm magenta.
Replaced this cycle.)
## 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 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).
Branch: master. v0.20.0 just cut on 2026-05-07; CHANGELOG's new
[Unreleased] section is empty pending the next cycle's threads.
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.
State: HEAD on the v0.20.0 docs commit. Tag not pushed yet — last
pushed tag is v0.19.0. Working tree clean apart from the
intentionally-untracked `artwork/`.
READ FIRST (in order, before doing anything):
1. SESSION_HANDOFF.md — this file
2. CHANGELOG.md — [Unreleased] holds the v0.20 draft
2. CHANGELOG.md — [0.20.0] section is the most recent cut
3. CLAUDE.md — unified-3.0 rule set
4. CLAUDE_SPEC.md — formal architecture spec
5. ARCHITECTURE.md — crate responsibilities + data flow
6. docs/android/* Android setup + build runbook (59424a3)
7. ~/.claude/projects/<this-project>/memory/MEMORY.md
6. docs/ui-mockups/design system + 24-mockup library
(Terminal aesthetic — landed in fa7f98a)
7. docs/android/* — Android setup + build runbook
8. ~/.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. 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
A. Push v0.20.0 tag — `git tag v0.20.0 && git push --tags`. If
the player wants the cut formalised before any new work.
B. APK launch verification — `adb install` + `adb logcat` on
bevy_test AVD or an x86_64 device. Now that persistence is
wired (4b51e50), shake out remaining runtime bugs.
C. Card-face artwork regeneration — generate Terminal-aesthetic
card PNGs (dark face, light suit pips), then migrate
CARD_FACE_COLOUR / RED_SUIT_COLOUR / BLACK_SUIT_COLOUR /
CARD_FACE_COLOUR_RED_CBM in lockstep. Largest visible
payoff remaining in the visual-identity arc.
D. Splash boot-loader richness — port the scanline overlay,
✓ check log, pulsing cursor, ROOT@SOLITAIRE prompt, and
loading bar from docs/ui-mockups/splash-mobile.html. Pure
polish; no behavioural change.
E. App icon round — re-run artwork/Icon Export.html (the
export PNGs are not currently in `artwork/`), 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.
F. JNI ClipboardManager / Keystore bridge — replaces the
Android stubs for Stats clipboard share + sync auth.
WORKFLOW NOTES:
- Use the system git config (already correct).
@@ -201,5 +278,5 @@ WORKFLOW NOTES:
- 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 AD. Don't pick unilaterally.
OPEN AT THE START: ask which of AF. Don't pick unilaterally.
```