fix(app): TDD bug sweep — vote correctness, feed races, stale-state fixes master
Test-first sweep of correctness bugs across voting, feeds, markdown rendering, and profile loading, hardened by a multi-model pre-merge review (/second-opinion) whose blocking findings are folded in. Voting: - Extract pure vote arithmetic into vote.ts with literal-oracle tests; fixes score computed as `upvotes` (downvotes ignored) and the stale voteUri carried across a direction switch; counters clamp at zero on desync with a warning instead of rendering negative counts. - CreateVoteOutput.uri/cid become optional, encoding the backend's create-as-toggle 200-without-uri case; both vote components resync from the pre-press snapshot and toast voteOutOfSync when it fires. - deleteVote 404 keeps the optimistic un-vote only for the backend's VoteNotFound error name; infrastructure 404s roll back and surface. - Vote components capture their subject before awaiting and discard settlements that land after the component shows a different subject. Feeds: - VirtualFeed: per-feed state (seenUris/hasMore/error) reseeds on feed identity change, and in-flight loadMore settlements for a departed feed are discarded instead of splicing the old feed's posts and cursor into the new one. - VirtualList: the height cache truncates when items shrink (was a documented-only defect); an emptied list clears visibleItems. Profile: - Loader scopes "user not found" to a getProfile 404 (bare i18n key); all other failures — including 404s from the posts/comments calls — propagate untouched. New loader tests cover every routing path plus the SvelteKit fetch pass-through. - UserActions: block state re-syncs on a DID+URI latch across navigation; toggleBlock guards re-entrancy, captures its subject across the await, and reports errors via errorMessage() with a 401 sessionExpired toast. App shell & UI: - sessionExpired flash cookie replaced by a locals-driven page.data flag with a repeat-toast latch. - Markdown options context uses live getters so inline/noStyle toggles reach mounted renderers; Popover passes positioning config through the floating-ui action argument so prop updates actually apply. - Init-time untrack() seeds and effect latches documented accurately (state_referenced_locally intent, not fictitious SSR/dependency mechanics); tsconfig drops the removed vite-plugin-pwa types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>