Main coves client

fix: harden session refresh, model parsing, retry policy, and routing master

Batch of five validated bug fixes plus follow-ups from a multi-model review (/second-opinion). Session refresh (the big one): a transient network/5xx failure during 401 recovery destroyed a valid session. Sign-out is now owned solely by AuthProvider.refreshToken(), which signs out only on definitive backend rejection (SessionExpiredException); both 401-recovery interceptors propagate refresh failures instead of signing out. The auth service also discards a stale refresh 401 when sign-out/re-login raced the request, so a stale 401 can never destroy the race winner's fresh session. Changes: - auth: sign out only on SessionExpiredException; interceptors no longer sign out on refresh failure (auth_interceptor, coves_api_service) - auth: race-discard identity check on the refresh failure path (coves_auth_service) - routing: comment sign-in flow used dead Navigator.pushNamed('/sign-in'); now context.push('/login') (comment_card) - config: read FLUTTER_APP_FLAVOR (the define Flutter actually injects); --flavor dev now selects the local backend (environment_config) - parsing: per-item skip-malformed guards with type-checked items and `on Object` (TypeError escapes `on Exception`) in CommentsResponse, ThreadViewComment replies, ActorCommentsResponse, CommunitiesResponse; tolerant cursor parsing - services: type-check uri/cid instead of casting in vote/comment services so a malformed response surfaces as ApiException and VoteProvider's optimistic rollback runs - retry: never retry non-idempotent methods on receiveTimeout or connectionError (ambiguous whether the server processed the request; prevents duplicate votes/comments); connectionTimeout stays retryable - docs: correct stale sign-out claims in CovesApiService header and getAccessToken - tests: regression coverage for all of the above (1137 pass; tests that pinned the old buggy behaviors updated to the new contract) Backend follow-up filed in the central backlog: HandleRefresh converts transient PDS failures into the 401 mobile reads as session death. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>