Every product page (discover, matches, chat, profile, photos) had the
same pattern: an `$effect` reads `nexo.session()`, then calls a
`load()` / `hydrate()` helper. Inside that helper Svelte's reactivity
tracks the `loading` / `profile` / etc. cells the helper writes to,
so when the helper finishes (sets `loading = false`) the effect sees
its own write and re-runs — and triggers the same fetch all over
again. Result: the dev server console fills with continuous
`/api/discover`, `/api/matches`, `/api/profile/me` requests as long
as the page is mounted.
Fix per page:
- **Discover, Matches**: introduce an `initialised` guard plus
`untrack(() => void load(...))`. The first session-ready transition
triggers the fetch; the helper's writes no longer feed back into
the effect.
- **Chat**: the trigger key is the URL `matchId` (it can change while
the page is mounted via in-app navigation). A `loadedFor` cell
holds the last id we fetched so a session-cell write doesn't
re-fetch the same thread, and the actual `load()` call is wrapped
in `untrack`.
- **Profile**: `hydrate()` populates eight reactive cells. Without
`untrack` the effect kept hydrating the form on every keystroke,
clobbering the user's edits. Now hydrated only when the profile id
changes.
- **Photos**: shallow-compare profile by `id + updated` before
re-assigning so identity-stable refreshes don't poke `$state`
proxies that downstream code reads.
The redirect branches (anonymous → /login, no-profile → /onboarding)
keep working because `goto` unmounts the current page, so the
mid-render effect simply stops running.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>