fix(multi): resolve 16 bugs from comprehensive rules and code review
Android Release / build-apk (push) Successful in 4m39s

Core (solitaire_core):
- fix(core): auto-complete now requires waste empty to prevent deadlock
- fix(core): reject multi-card moves from waste pile (Klondike rule)
- fix(core): reject foundation-to-foundation moves (score farming exploit)
- fix(core): undo restores score from snapshot baseline, not live score
- feat(scoring): add +5 flip bonus when face-down tableau card is exposed
- feat(scoring): add recycle penalty (Draw-1: -100/pass, Draw-3: -20/pass)

Engine (solitaire_engine):
- fix(engine): remove TokioRuntimeResource::default() panic; degrade gracefully
- fix(engine): add ModalScrim guard to handle_new_game spawn site
- fix(engine): add ModalScrim guard to spawn_restore_prompt spawn site
- fix(engine): add ModalScrim guard to check_no_moves spawn site

Server / Web (solitaire_server):
- fix(web): correct draw_mode casing in replay submission (DrawOne/DrawThree)
- fix(web): correct mode casing in replay submission (Classic) for leaderboard
- fix(web): trim recorded_at to YYYY-MM-DD for NaiveDate deserialization
- fix(server): move /avatars route outside auth middleware (was always 401)

Data / Sync (solitaire_data, solitaire_sync):
- fix(data): namespace Android token file under APP_DIR_NAME with migration
- fix(data): Android token store now multi-user (HashMap); no silent overwrite
- fix(sync): draw_one_wins + draw_three_wins invariant preserved after merge

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
funman300
2026-05-19 16:27:04 -07:00
parent f6e7de1093
commit e50ff02274
10 changed files with 531 additions and 135 deletions
+13 -2
View File
@@ -48,10 +48,21 @@ pub struct AvatarPlugin;
impl Plugin for AvatarPlugin {
fn build(&self, app: &mut App) {
app.add_message::<AvatarFetchEvent>()
.init_resource::<TokioRuntimeResource>()
.init_resource::<AvatarResource>()
.init_resource::<PendingAvatarTask>()
.add_systems(Update, (handle_avatar_fetch, poll_avatar_task));
.add_systems(Update, poll_avatar_task);
// Build the shared Tokio runtime; skip avatar download if the OS
// refuses to create threads (resource-limited / sandboxed environments).
match TokioRuntimeResource::new() {
Ok(rt) => {
app.insert_resource(rt)
.add_systems(Update, handle_avatar_fetch);
}
Err(e) => {
bevy::log::warn!("avatar_plugin: Tokio runtime unavailable — avatar fetch disabled: {e}");
}
}
}
}