diff --git a/neode-ui/src/views/Apps.vue b/neode-ui/src/views/Apps.vue index 1993cfc6..dd4a2838 100644 --- a/neode-ui/src/views/Apps.vue +++ b/neode-ui/src/views/Apps.vue @@ -380,7 +380,7 @@ let appsAnimationDone = false diff --git a/neode-ui/src/views/dashboard/keepAliveRoutes.ts b/neode-ui/src/views/dashboard/keepAliveRoutes.ts index ea3d81c7..67825299 100644 --- a/neode-ui/src/views/dashboard/keepAliveRoutes.ts +++ b/neode-ui/src/views/dashboard/keepAliveRoutes.ts @@ -8,21 +8,58 @@ // `server/openwrt`, `web5/credentials`, `goals/:goalId` and `app-session/:appId`. import type { RouteLocationNormalizedLoaded } from 'vue-router' +import { TAB_ORDER } from './useRouteTransitions' /** Maximum number of main-tab component instances kept alive at once (D-03). * Bounds memory on low-power fleet nodes — the oldest unused instance evicts - * once this cap is exceeded (Vue's own LRU eviction). */ + * once this cap is exceeded (Vue's own LRU eviction). Stays at 6 against the + * ~11 registered paths below (FA-D) — plan 02-08 tunes it against real + * on-device memory, not guessed at again here. */ export const KEEP_ALIVE_MAX = 6 -/** Paths whose component instance survives a tab switch (D-01). +/** TAB_ORDER paths deliberately withheld from the instance cache this plan + * (02-04) would otherwise register. Two distinct reasons populate this set — + * kept in one place so `KEEP_ALIVE_PATHS` stays a single derivation: * - * Seeded with only the tracer tab (Marketplace) for this plan — plan 02-04 - * widens this set after auditing every main tab's mount/activate lifecycle. - * Do not add paths here without doing that audit first: a view with an - * un-audited side effect in `onMounted` that should have moved to - * `onActivated`/`onDeactivated` would misbehave the moment it's kept alive. */ + * 1. Measured `already fast` in 02-FINDINGS.md with `Remounted: false` — no + * instance cache to gain (D-02). (None as of 02-04: every TAB_ORDER path + * measured `Remounted: true` (Home, Apps, Marketplace, Cloud, Web5, + * Fleet) or was `unmeasured` (Mesh, Chat) — neither unmeasured row has a + * `Remounted: false`, so per the plan's literal exclusion rule both stay + * registered, and their lifecycle was audited in 02-04's Task 1.) + * 2. Unaudited-risk (02-04 Rule-3 deviation, not in 02-FINDINGS.md at all): + * `/dashboard/settings` is in TAB_ORDER but neither Settings.vue nor any + * of its child sections are in this plan's Task 1/2 file lists. A grep + * across `neode-ui/src/views/settings/*.vue` found real un-audited side + * effects that would misbehave under KeepAlive exactly as this plan + * warns against: `SystemDangerZone.vue`'s reboot poll/elapsed intervals, + * and one-shot `onMounted`-only fetches in `VpnStatusSection.vue`, + * `KioskDisplaySection.vue`, `TransportPrefsCard.vue` and + * `ClaudeAuthSection.vue` that would never refresh again once cached. + * Registering Settings without that audit would ship the exact + * off-screen-timer/stale-data bug this plan exists to prevent — excluded + * until a future plan audits it the way Task 1 did for Home/Web5/Chat/ + * Cloud/Server/Mesh. */ +const WITHHELD_FROM_CACHE: ReadonlySet = new Set([ + '/dashboard/settings', +]) + +/** Paths whose component instance survives a tab switch (D-01), derived from + * the single-sourced TAB_ORDER main-tab list (plus `/dashboard/discover`, + * the App Store's second tab, measured `remount storm` in 02-FINDINGS.md but + * not part of TAB_ORDER) rather than restating every path literally — a + * future tab addition to TAB_ORDER is registered automatically instead of + * silently missing registration. + * + * 02-04 widened this from the 02-02 tracer's single seed path after + * auditing every main tab's mount/activate/deactivate lifecycle (see + * 02-04-SUMMARY.md's per-view side-effect table) — every registered path's + * timers, subscriptions and window listeners are now placed for an + * activate/deactivate lifecycle, so it's safe for their instances to + * survive a tab switch. */ export const KEEP_ALIVE_PATHS: ReadonlySet = new Set([ - '/dashboard/marketplace', + ...TAB_ORDER.filter((path) => !WITHHELD_FROM_CACHE.has(path)), + '/dashboard/discover', ]) /** True only for an exact path match against KEEP_ALIVE_PATHS. */