docs(02-06): complete Server and Home tab cache plan
This commit is contained in:
parent
926fa60691
commit
8205e9f142
@ -73,7 +73,7 @@ Plans:
|
||||
3. Secondary screens open without a blocking full reload; repeat visits are instant
|
||||
4. The fixes are verified on real node hardware (not just the dev box) — the sluggishness the user reported is gone on-device
|
||||
|
||||
**Plans**: 5/8 plans executed
|
||||
**Plans**: 6/8 plans executed
|
||||
|
||||
Plans:
|
||||
**Wave 1**
|
||||
@ -92,7 +92,7 @@ Plans:
|
||||
**Wave 4** *(blocked on Wave 3 completion)*
|
||||
|
||||
- [x] 02-05-PLAN.md — Mesh: cache the six fetch groups, bound the D3 graph and Leaflet map (PERF-02)
|
||||
- [ ] 02-06-PLAN.md — Server and Home: cache the uncached fan-out, guarantee wallet freshness (PERF-02)
|
||||
- [x] 02-06-PLAN.md — Server and Home: cache the uncached fan-out, guarantee wallet freshness (PERF-02)
|
||||
- [ ] 02-07-PLAN.md — Chat/AIUI: stable embed URL + the two D-14 UX defaults (PERF-02)
|
||||
|
||||
**Wave 5** *(blocked on Wave 4 completion)*
|
||||
@ -196,7 +196,7 @@ Phases execute in numeric order: 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8
|
||||
| Phase | Plans Complete | Status | Completed |
|
||||
|-------|----------------|--------|-----------|
|
||||
| 1. Federation & Mesh Hardening | 0/10 | Planned | - |
|
||||
| 2. UI Performance | 5/8 | In Progress| |
|
||||
| 2. UI Performance | 6/8 | In Progress| |
|
||||
| 3. Multinode Verification Pass | 0/TBD | Not started | - |
|
||||
| 4. Lifecycle Perfection & Quadlet Default | 0/TBD | Not started | - |
|
||||
| 5. Registry-Distributed Manifests | 0/TBD | Not started | - |
|
||||
|
||||
@ -5,15 +5,15 @@ milestone_name: milestone
|
||||
current_phase: 02
|
||||
current_phase_name: ui-performance
|
||||
status: executing
|
||||
stopped_at: Completed 02-05-PLAN.md
|
||||
last_updated: "2026-07-30T20:24:44.908Z"
|
||||
stopped_at: Completed 02-06-PLAN.md
|
||||
last_updated: "2026-07-30T21:41:43.379Z"
|
||||
last_activity: 2026-07-30
|
||||
last_activity_desc: Phase 02 execution started
|
||||
progress:
|
||||
total_phases: 8
|
||||
completed_phases: 0
|
||||
total_plans: 18
|
||||
completed_plans: 5
|
||||
completed_plans: 6
|
||||
percent: 0
|
||||
---
|
||||
|
||||
@ -29,11 +29,11 @@ See: .planning/PROJECT.md (updated 2026-07-29)
|
||||
## Current Position
|
||||
|
||||
Phase: 02 (ui-performance) — EXECUTING
|
||||
Plan: 5 of 8
|
||||
Plan: 6 of 8
|
||||
Status: Ready to execute
|
||||
Last activity: 2026-07-30 — Phase 02 execution started
|
||||
|
||||
Progress: [███░░░░░░░] 28%
|
||||
Progress: [███░░░░░░░] 33%
|
||||
|
||||
## Performance Metrics
|
||||
|
||||
@ -57,6 +57,7 @@ Progress: [███░░░░░░░] 28%
|
||||
| Phase 02 P02 | 105min | 3 tasks | 11 files |
|
||||
| Phase 02 P04 | 150min | 3 tasks | 12 files |
|
||||
| Phase 02 P05 | 50min | 2 tasks | 8 files |
|
||||
| Phase 02 P06 | 73min | 2 tasks | 7 files |
|
||||
|
||||
## Accumulated Context
|
||||
|
||||
@ -93,6 +94,10 @@ Decisions are logged in PROJECT.md (10 locked ADRs in the `<decisions>` block +
|
||||
- [Phase ?]: 02-05: mesh.refreshAll()/transport.fetchStatus() stay uncached at the store level (other callers need guaranteed-fresh reads); the useCachedResource wrapper around each lives in Mesh.vue instead, since Pinia's defineStore(id,setup) runs in a bare effectScope where onActivated() silently no-ops
|
||||
- [Phase ?]: 02-05: FLAGGED - RESEARCH.md's premise that Mesh.vue owns a D3 force simulation is incorrect for this codebase (verified via grep); only NetworkMap.vue/Federation.vue has one. Task 2's D3 truths are vacuously satisfied; only the real Leaflet map lifecycle (MeshMap.vue, added to scope) was implemented
|
||||
- [Phase ?]: 02-05: per-group TTL/persist table - mesh.refresh-all/federation-nodes/self-onion/self-did/contacts all persist:false (identity payload); transport-status persists (aggregate, non-identity); reachability groups get 10s TTL, identity groups 300s
|
||||
- [Phase ?]: 02-06: RESEARCH A3 settled — none of Server's seven load-group loaders consumes another's result; concurrent fan-out is correct as-is
|
||||
- [Phase ?]: 02-06: Five of Server's seven groups were already on useCachedResource from a pre-phase legacy commit (ea254f63) with only composable defaults (30s TTL, persist:true) — this plan's work was explicit TTL/persist/dedup, not initial conversion; only loadDiskStatus was a genuinely uncached plain fetch
|
||||
- [Phase ?]: 02-06: Home's wallet composite does NOT share a cache key with Web5.vue's web5.lnd-info — sharing would either corrupt Web5's typed entry.data or fail to close the sessionStorage gap since Web5.vue's own hook (out of scope) defaults persist:true
|
||||
- [Phase ?]: 02-06: homeStatus.refresh() wrapped by useCachedResource at Home.vue (the view), not inside the homeStatus Pinia store — defineStore(id,setup) runs in a bare effectScope where onActivated() silently no-ops, same finding as 02-05's Mesh.vue
|
||||
|
||||
### Pending Todos
|
||||
|
||||
@ -127,6 +132,6 @@ None yet.
|
||||
|
||||
## Session Continuity
|
||||
|
||||
Last session: 2026-07-30T20:24:44.884Z
|
||||
Stopped at: Completed 02-05-PLAN.md
|
||||
Last session: 2026-07-30T21:41:43.362Z
|
||||
Stopped at: Completed 02-06-PLAN.md
|
||||
Resume file: None
|
||||
|
||||
220
.planning/phases/02-ui-performance/02-06-SUMMARY.md
Normal file
220
.planning/phases/02-ui-performance/02-06-SUMMARY.md
Normal file
@ -0,0 +1,220 @@
|
||||
---
|
||||
phase: 02-ui-performance
|
||||
plan: 06
|
||||
subsystem: ui
|
||||
tags: [vue, useCachedResource, sessionstorage, pinia, wallet, rpc-dedup]
|
||||
|
||||
# Dependency graph
|
||||
requires:
|
||||
- phase: 02-ui-performance/02-02
|
||||
provides: "useCachedResource composable (TTL/persist/onActivated revalidation), RefreshIndicator.vue, the explicit-per-key persist convention"
|
||||
- phase: 02-ui-performance/02-04
|
||||
provides: "Server.vue's vpnPollInterval and loadDiskStatus placed on activate/deactivate; Home.vue's systemStatsInterval/walletRefreshInterval/wsClient subscription placed on activate/deactivate with an immediate re-sync on entry"
|
||||
- phase: 02-ui-performance/02-05
|
||||
provides: "The 'host useCachedResource at the component, not inside a Pinia store setup' finding (onActivated no-ops in a bare effectScope), and the side-effect-only/sentinel-timestamp resource pattern for wrapping an existing function that sets its own refs"
|
||||
provides:
|
||||
- "All seven Server.vue load groups (network summary, FIPS summary, VPN peers, interfaces, Tor services — shared by checkTorStatus/loadTorServices — and disk status) on useCachedResource with explicit per-group TTL and persist"
|
||||
- "Home.vue's system stats, update status and cloud storage usage on every-entry TTL-gated useCachedResource entries"
|
||||
- "Home.vue's wallet composite fetch on a persist:false useCachedResource that revalidates unconditionally on every activation (T-02-13)"
|
||||
- "RefreshIndicator wired into both Server's and Home's headers"
|
||||
affects: [02-08]
|
||||
|
||||
# Tech tracking
|
||||
tech-stack:
|
||||
added: []
|
||||
patterns:
|
||||
- "A pre-existing (pre-phase) useCachedResource conversion can lack explicit TTL/persist — auditing for that gap before assuming a plan's own conversion work is still needed"
|
||||
- "refreshHomeGroupIfStale/homeCachedGroups — the Home.vue instance of the refreshMeshGroupIfStale generalized staleness-gate pattern from 02-05, applied via Promise.allSettled"
|
||||
- "A cached resource with no ttlMs relied on for staleness gating at all, because the view always calls refresh() unconditionally on activation (the wallet-freshness exception to the default stale-while-revalidate contract)"
|
||||
|
||||
key-files:
|
||||
created:
|
||||
- neode-ui/src/views/__tests__/serverTabCache.test.ts
|
||||
- neode-ui/src/views/__tests__/homeTabCache.test.ts
|
||||
modified:
|
||||
- neode-ui/src/views/Server.vue
|
||||
- neode-ui/src/views/Home.vue
|
||||
- neode-ui/src/stores/homeStatus.ts
|
||||
- neode-ui/src/api/rpc-client.ts
|
||||
- neode-ui/src/views/dashboard/__tests__/keepAliveLifecycle.test.ts
|
||||
|
||||
key-decisions:
|
||||
- "RESEARCH assumption A3 settled: read all seven Server loader bodies (checkTorStatus, loadNetworkData, loadInterfaces, loadVpnPeers, loadFipsSummary, loadTorServices, loadDiskStatus) — none consumes another's result or side effect (networkRes's fetcher only reads its OWN previous value for merge purposes, which is self-referential, not cross-resource). The concurrent fan-out is correct as originally written; no aggregate endpoint or ordering was needed."
|
||||
- "Five of Server's seven groups (network-summary, fips-summary, vpn-peers, interfaces, tor-services) were ALREADY on useCachedResource from a pre-phase legacy commit (ea254f63, predates this milestone) but relied entirely on the composable's defaults (30s TTL, persist:true) — this task's real work was adding explicit per-group TTL/persist/dedup, not the initial conversion. Only loadDiskStatus was a genuinely uncached plain fetch."
|
||||
- "Home's wallet composite (lnd.getinfo + ecash/fedimint/ark balances + 3 histories) does NOT share a cache key with either of Web5.vue's two existing resources (web5.networking-profits, web5.lnd-info). web5.networking-profits is an unrelated dataset. web5.lnd-info covers only the single lnd.getinfo call and — critically — is declared with the composable's implicit default persist:true; Web5.vue is out of this plan's file scope to fix, so sharing that key would either corrupt its differently-shaped entry.data (Home's sentinel timestamp vs. its typed balance object) or silently fail to close the sessionStorage gap this task exists to close, since Web5.vue's own hook instance would keep persisting on its own independent refresh cycle regardless of what Home declares."
|
||||
- "homeStatus.refresh() and (in Mesh.vue's 02-05 precedent) mesh.refreshAll()/transport.fetchStatus() are both Pinia store actions wrapped by a useCachedResource hosted at the VIEW, not inside the store — defineStore(id, setup) runs in a bare effectScope where onActivated() silently no-ops (Vue dev warning only), so the wrapper must live where the real component/KeepAlive lifecycle is."
|
||||
- "dedup:true added directly inside vpnStatus()/dnsStatus()/diskStatus() in rpc-client.ts (parameterless convenience methods with no per-call options), following the existing in-file precedent at getNodeDid()/meshContactsList()/federationListNodes()."
|
||||
|
||||
patterns-established:
|
||||
- "Before assuming a plan's list of 'uncached load groups' needs full conversion, grep for existing useCachedResource usage in the target file — legacy or prior-plan work may have already wired the hook without the TTL/persist/dedup decisions a later plan is tasked with adding."
|
||||
|
||||
requirements-completed: []
|
||||
requirements-note: "PERF-02 is NOT marked complete — 02-07 (Chat/AIUI) still extends the KeepAlive/cache architecture to the one remaining unconverted main tab, per the precedent set by 02-02/02-03/02-04/02-05's own summaries."
|
||||
|
||||
coverage:
|
||||
- id: D1
|
||||
description: "All seven Server.vue load groups (network summary, FIPS summary, VPN peers, interfaces, Tor services, disk status, plus checkTorStatus sharing tor-services) are cached with explicit TTL/persist; a revisit inside TTL issues zero RPC across all seven, a cold load still fires the independent groups concurrently, and a rejected group leaves the other six unaffected"
|
||||
requirement: PERF-02
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "neode-ui/src/views/__tests__/serverTabCache.test.ts"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D2
|
||||
description: "VPN peers (npub) and Tor services (onion addresses) declare persist:false; network-summary/fips-summary/interfaces/disk-status (no identity payload) persist; every fetcher backing the seven groups passes dedup:true; RefreshIndicator renders in the Server header driven by any group refreshing"
|
||||
requirement: PERF-02
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "neode-ui/src/views/__tests__/serverTabCache.test.ts"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D3
|
||||
description: "Home's system stats, update status and cloud storage usage are every-entry, TTL-gated cached resources; a revisit inside TTL issues zero new RPCs for those three groups"
|
||||
requirement: PERF-02
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "neode-ui/src/views/__tests__/homeTabCache.test.ts"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D4
|
||||
description: "The wallet composite (home.wallet-status) revalidates unconditionally on every reactivation regardless of TTL, the previously rendered figure stays in the DOM throughout, persist:false (no sessionStorage key), hydrateWalletSnapshot still paints before any network round-trip, the websocket wallet-push path is intact, and RefreshIndicator binds to the wallet resource's loadState"
|
||||
requirement: PERF-02
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "neode-ui/src/views/__tests__/homeTabCache.test.ts"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
- id: D5
|
||||
description: "No visual/animation regression — full suite (94 files / 767 tests incl. the structural keepAliveTabs.test.ts DOM-shape pin) stays green, type-check and build are clean, and the built bundle contains the new resource keys"
|
||||
requirement: PERF-02
|
||||
verification:
|
||||
- kind: unit
|
||||
ref: "npm run test (94 files / 767 tests)"
|
||||
status: pass
|
||||
- kind: other
|
||||
ref: "npm run type-check && npm run build; grep for home.wallet-status/home.system-stats/home.update-status/home.cloud-usage/server.disk-status in web/dist/neode-ui/assets/{Home,Server}-*.js"
|
||||
status: pass
|
||||
human_judgment: false
|
||||
|
||||
duration: 73min
|
||||
completed: 2026-07-30
|
||||
status: complete
|
||||
---
|
||||
|
||||
# Phase 02 Plan 06: Server and Home Tab Cache Summary
|
||||
|
||||
**Server's seven load groups (five already on useCachedResource from a pre-phase commit, gaining their first explicit TTL/persist/dedup here; disk status newly converted) and Home's system/update/storage groups on every-entry TTL-gated cache, with the wallet composite on an unconditional-revalidate-on-entry resource that never persists to sessionStorage**
|
||||
|
||||
## Performance
|
||||
|
||||
- **Duration:** ~73 min
|
||||
- **Started:** 2026-07-30T20:26:48Z
|
||||
- **Completed:** 2026-07-30T21:39:25Z
|
||||
- **Tasks:** 2 (Task 1 auto/tdd, Task 2 auto/tdd)
|
||||
- **Files modified:** 7 (2 new test files, 5 modified)
|
||||
|
||||
## Accomplishments
|
||||
|
||||
- **RESEARCH A3 settled (Server.vue):** read every one of the seven loader bodies — `checkTorStatus`, `loadNetworkData`, `loadInterfaces`, `loadVpnPeers`, `loadFipsSummary`, `loadTorServices`, `loadDiskStatus`. None consumes another's result or side effect; `networkRes`'s fetcher reads only its OWN previous cached value to merge partial RPC results, which is self-referential, not a cross-resource dependency. Verdict: independent, concurrent fan-out is correct as-is — no aggregate endpoint or ordering change was needed.
|
||||
- **Found: 5 of Server's 7 groups were already on `useCachedResource`** from a pre-phase legacy commit (`ea254f63`, predates this UI-performance milestone) — `networkRes`, `fipsSummaryRes`, `vpnPeersRes`, `interfacesRes`, `torServicesRes`. None had an explicit `ttlMs`/`persist` (relying on the composable's 30s/`persist:true` defaults), and several underlying calls lacked `dedup:true`. `checkTorStatus()` turned out to just call `torServicesRes.refresh()` and derive a label — it shares that resource rather than being an eighth key. Only `loadDiskStatus()` was a genuinely uncached plain fetch, forced on every activation.
|
||||
- **Server.vue's per-group TTL/persist table** (all explicit, none defaulted, per T-02-01):
|
||||
|
||||
| Key | TTL | Persist | Reason |
|
||||
|---|---|---|---|
|
||||
| `server.network-summary` | 10,000ms | `true` | Fast tier (WiFi/VPN/DNS state); this node's own status/wgPubkey, not peer identity |
|
||||
| `server.interfaces` | 10,000ms | `true` | Fast tier; local hardware info (MAC/IP), no identity |
|
||||
| `server.disk-status` | 10,000ms | `true` | Fast tier; usage figures carry no identity/financial payload |
|
||||
| `server.vpn-peers` | 30,000ms | `false` | Near-default; carries npub (peer Nostr identity) |
|
||||
| `server.tor-services` | 30,000ms | `false` | Near-default; carries onion_address |
|
||||
| `server.fips-summary` | 60,000ms | `true` | Near-static (installed/service_active/key_present rarely change; authenticated_peer_count can drift, so not fully static); key_present is a boolean flag, not the key itself |
|
||||
|
||||
- **Home.vue's cache keys** (all hosted in Home.vue, not inside the `homeStatus` Pinia store — a store's `defineStore(id, setup)` runs in a bare effectScope where `onActivated()` silently no-ops, the same finding 02-05 made for Mesh's store actions):
|
||||
|
||||
| Key | Wraps | TTL | Persist | Reason |
|
||||
|---|---|---|---|---|
|
||||
| `home.system-stats` | `homeStatus.refresh(packages)` (system/bitcoin/vpn/fips/tollgate, 5 RPCs) | 10,000ms | `true` | Matches the pre-existing 10s poll cadence; aggregate status, no identity |
|
||||
| `home.update-status` | `checkUpdateStatus()` | 300,000ms | `true` | Near-static; an available update doesn't appear/disappear quickly |
|
||||
| `home.cloud-usage` | `fileBrowserClient.getUsage()` | 30,000ms | `true` | Default tier; non-sensitive |
|
||||
| `home.wallet-status` | `loadWeb5Status()` (7-call composite: lnd.getinfo + ecash/fedimint/ark balances + 3 histories) | n/a — never TTL-gated, always unconditional | `false` | T-02-13 exception: a money figure must never be presented as current without a visible re-check |
|
||||
|
||||
- **Web5.vue key-sharing evaluated and declined** (read both of its resources): `web5.networking-profits` is an unrelated dataset (routing/content-sale profit totals). `web5.lnd-info` covers only the single `lnd.getinfo` call and — the reason sharing was declined — is declared with the composable's implicit default `persist:true`; Web5.vue is outside this plan's file scope to fix, so sharing that key would either corrupt its differently-shaped `entry.data` (a sentinel timestamp here vs. its typed balance object there) or silently fail to close the sessionStorage gap this task exists to close, since Web5.vue's own hook instance would keep persisting on its own independent 30s-interval refresh regardless of what Home declares. Home's wallet fetch is also a strictly broader 7-call composite, not the same single-call dataset.
|
||||
- **`dedup:true` added to every underlying RPC call touched by this plan**: Server's `network.diagnostics`/`router.list-forwards` (inline in `networkRes`'s fetcher) plus `vpnStatus()`/`dnsStatus()`/`diskStatus()` (parameterless convenience methods in `rpc-client.ts`, given `dedup:true` directly in their bodies, matching the existing `getNodeDid()`/`meshContactsList()` precedent); Home's 7-call wallet composite and `checkUpdateStatus()`'s two calls; `homeStatus.ts`'s `system.stats`/`bitcoin.getinfo`/`fips.status`/`openwrt.get-status` (its `vpn.status` call already picked up `dedup:true` for free via the `vpnStatus()` change).
|
||||
- **`RefreshIndicator` wired into both headers**: Server gained a new minimal top-of-page row (it previously had no visible page header at all — its `QuickActionsCard` header is `v-if="false"`); Home's got added inline next to the existing typed-welcome `<h1>`, both driven by a `loadState`-derived computed (`serverRefreshIndicatorState` = any of six groups refreshing; `homeRefreshIndicatorState` = the wallet resource's own `loadState`, directly — the wallet is the one group whose refresh visibility matters most, per T-02-13).
|
||||
- **Server's `loadDiskStatus()` converted** to the seventh `useCachedResource` entry (`server.disk-status`); `armServerEntryEffects()` no longer force-calls it on every activation — the resource's own internal `onActivated` (added in 02-02) now self-heals it staleness-gated, exactly like the other six.
|
||||
- **Home's `armLiveDataPolling()`** restructured around `homeCachedGroups`/`refreshHomeGroupIfStale` (the 02-05 `refreshMeshGroupIfStale` pattern), kicked via a single `Promise.allSettled` — the plan's required move of `fileBrowserClient.getUsage()`'s trailing `await` into the same concurrent fan-out as the other loaders.
|
||||
|
||||
## Task Commits
|
||||
|
||||
Each task was committed atomically:
|
||||
|
||||
1. **Task 1: Cache the Server tab's seven load groups** - `e6ed5536` (feat, tdd)
|
||||
2. **Task 2: Cache the Home tab and guarantee wallet freshness on re-entry** - `926fa606` (feat, tdd)
|
||||
|
||||
**Plan metadata:** (this commit) - `docs(02-06): complete Server and Home tab cache plan`
|
||||
|
||||
_Note: both tasks are TDD tasks; tests were written and made to pass within each task's own commit, per this repo's established single-commit-per-task convention (see 02-01 through 02-05 history)._
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `neode-ui/src/views/Server.vue` — explicit TTL/persist added to the five pre-existing cached resources; `loadDiskStatus` converted to a sixth-and-seventh (`server.disk-status`) cached resource; `dedup:true`/signal threaded through `networkRes`'s two inline calls; `RefreshIndicator` added to a new minimal header row; `armServerEntryEffects`/`onMounted` comments updated to reflect the settled A3 verdict
|
||||
- `neode-ui/src/views/Home.vue` — `systemStatsRes`/`updateStatusRes`/`cloudUsageRes`/`walletStatusRes` added; `armLiveDataPolling` restructured around `homeCachedGroups`/`refreshHomeGroupIfStale` + unconditional wallet refresh; `onMounted` no longer `async`/no trailing `await`; `dedup:true` added to the wallet composite and `checkUpdateStatus`'s calls; `RefreshIndicator` added next to the header `<h1>`; new `defineExpose` block (`loadWeb5Status`, `homeRefreshIndicatorState`) for test access
|
||||
- `neode-ui/src/stores/homeStatus.ts` — `dedup:true` added to `system.stats`/`bitcoin.getinfo`/`fips.status`/`openwrt.get-status`
|
||||
- `neode-ui/src/api/rpc-client.ts` — `dedup:true` added inside `vpnStatus()`/`dnsStatus()`/`diskStatus()`
|
||||
- `neode-ui/src/views/__tests__/serverTabCache.test.ts` — new; 7 tests covering Task 1's five required behaviors plus persist/dedup/indicator-wiring assertions
|
||||
- `neode-ui/src/views/__tests__/homeTabCache.test.ts` — new; 8 tests covering Task 2's six required behaviors plus dedup/websocket-path assertions
|
||||
- `neode-ui/src/views/dashboard/__tests__/keepAliveLifecycle.test.ts` — one assertion fixed (see Deviations): the pre-existing Server.vue `vpnPollInterval` test's reactivation count was invalidated by `server.network-summary`'s new explicit 10s TTL
|
||||
|
||||
## Decisions Made
|
||||
|
||||
See `key-decisions` in frontmatter for the full list. Highlights:
|
||||
- RESEARCH A3 settled (independent, no ordering dependency) — see Accomplishments.
|
||||
- Five of Server's seven groups were already converted by a pre-phase legacy commit; this task's real work was explicit TTL/persist/dedup, not the initial `useCachedResource` wiring.
|
||||
- Web5.vue key-sharing evaluated and declined for a documented, safety-driven reason (would either corrupt Web5's typed entry or fail to close the sessionStorage gap).
|
||||
- `homeStatus.refresh()` wrapped at the view (Home.vue), not inside the store, per the 02-05 Pinia-effectScope finding.
|
||||
|
||||
## Deviations from Plan
|
||||
|
||||
### Auto-fixed Issues
|
||||
|
||||
**1. [Rule 1 - Bug, caught by the existing test suite] `keepAliveLifecycle.test.ts`'s Server.vue vpnPollInterval reactivation count invalidated by the new explicit TTL**
|
||||
- **Found during:** Task 1, full-suite run after adding `networkRes`'s explicit 10s TTL
|
||||
- **Issue:** The pre-existing test deactivated Server for 20s (chosen, per its own comment, to be "comfortably under networkRes's [then-default] 30s TTL"). Once `server.network-summary` got an explicit 10s TTL, that 20s deactivation window now makes `networkRes` itself stale, so reactivation triggers a SECOND `vpnStatus()` call (via `networkRes`'s own `onActivated` revalidation) in addition to `armVpnPoll`'s immediate tick — the test's `+1` assertion needed to become `+2`.
|
||||
- **Fix:** Updated the assertion and its comment to explain both contributing calls.
|
||||
- **Files modified:** `neode-ui/src/views/dashboard/__tests__/keepAliveLifecycle.test.ts`
|
||||
- **Verification:** Full suite green (94 files / 767 tests) after the fix.
|
||||
- **Committed in:** `e6ed5536` (Task 1 commit)
|
||||
|
||||
---
|
||||
|
||||
**Total deviations:** 1 auto-fixed (Rule 1 — a test assertion directly invalidated by this task's own required TTL change)
|
||||
**Impact on plan:** Necessary correction within a file this task's change directly affected. No scope creep — the fix only updates an assertion and its explanatory comment.
|
||||
|
||||
## Known Stubs
|
||||
|
||||
None — no stub data, placeholder text, or unwired data sources were introduced. Every cached group's fetcher performs a real RPC round-trip (or wraps an existing store/view function that does).
|
||||
|
||||
## Threat Flags
|
||||
|
||||
None beyond what the plan's own `<threat_model>` already anticipated (T-02-01, T-02-13, T-02-16, T-02-17) — no new network endpoints, auth paths, or trust-boundary-crossing surface was introduced by this plan.
|
||||
|
||||
## Issues Encountered
|
||||
|
||||
- The `keepAliveLifecycle.test.ts` assertion invalidation above — resolved by updating the test to match the new, plan-mandated TTL behavior; no production-code bug.
|
||||
- `flushPromises()` (a single macrotask boundary) needed to be called twice in `homeTabCache.test.ts` to fully settle `loadWeb5Status()`'s deeply nested `Promise.allSettled` chains under fake timers before the wallet resource's `loadState` reliably reached `'ready'` — a test-authoring detail (`settle()` helper), not a production bug.
|
||||
- A leaking permanent `mockImplementation()` override (used by one test to simulate a never-resolving RPC) was caught before commit — `beforeEach` now unconditionally restores the default mock implementation alongside `mockClear()`.
|
||||
|
||||
## User Setup Required
|
||||
|
||||
None - no external service configuration required.
|
||||
|
||||
## Next Phase Readiness
|
||||
|
||||
- Every main tab in `KEEP_ALIVE_PATHS` except Chat/AIUI now has its data layer on `useCachedResource` with explicit TTL/persist decisions (Marketplace/Discover 02-02, secondary screens 02-03, Mesh 02-05, Server/Home this plan) — 02-07 (Chat/AIUI) is the one remaining conversion.
|
||||
- The "host `useCachedResource` at the component, not inside a Pinia store setup" finding (02-05, reconfirmed here for `homeStatus.ts`) is now established across two independent stores — a strong signal for 02-08's on-device pass to treat as settled architecture, not a per-case judgment call.
|
||||
- No blockers for 02-07/02-08.
|
||||
|
||||
---
|
||||
*Phase: 02-ui-performance*
|
||||
*Completed: 2026-07-30*
|
||||
|
||||
## Self-Check: PASSED
|
||||
Loading…
x
Reference in New Issue
Block a user