Coves frontend - a photon fork

fix(feeds): migrate sort controls to Coves API and fix feed cache staleness master

The community feed's sort selector rendered blank and sorting silently fell back to "hot": PostListShell still used the legacy Lemmy selector (capitalized values like TopAll) while the loaders speak lowercase Coves sorts. Fixing that surfaced deeper issues — a route-level feed cache that could serve the wrong community after client-side navigation, and persisted settings polluted with legacy values. A six-reviewer multi-model pass then hardened the settings import path and the cache's concurrency semantics. Changes: - Replace legacy Sort.svelte/Location.svelte with the Coves-native SortMenu (hot/top/new + hour..all timeframes) in PostListShell and settings; migrate command palette entries to valid sort/type URLs - Fix stale feed cache: init closures read only their load() params, feed() refreshes the cached fetcher (setFetch), and a generation counter discards superseded fetch results/errors - Make settings.defaultSort a live, validated setting: resolveFeedSort gives URL params precedence, applies the saved timeframe only when sort came from settings, and grace-maps legacy URLs (?sort=TopWeek) - Persist defaults only on explicit user selection (SortMenu/FeedTabs, after successful navigation) so shared links and legacy bookmarks can't rewrite a viewer's saved preferences - Harden settings import: plain-object check, detached mergeDeep candidate (drops __proto__/unknown keys, CWE-1321), total normalizers that never throw on foreign input; clone on reset; guard localStorage writes (private-mode Safari) - Normalize legacy persisted values (New/TopAll/Subscribed→timeline) on load and import; tighten settings types to the Coves unions - Single TIMEFRAME_OPTIONS source of truth (type + validation derived); add hour/year timeframes end to end - Tests: 45 new across feed cache races, loader regressions, resolveFeedSort precedence, normalizers, and settings import (759 passing) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>