Files
archy/.planning/phases/02-ui-performance/02-VALIDATION.md
T

135 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
phase: 2
slug: ui-performance
# status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6)
# audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117)
status: draft
nyquist_compliant: false
wave_0_complete: false
created: 2026-07-30
---
# Phase 2 — Validation Strategy
> Per-phase validation contract for feedback sampling during execution.
> Backfilled from the 8 plans' actual `<verify><automated>` blocks (02-01 … 02-08).
---
## Test Infrastructure
| Property | Value |
|----------|-------|
| **Framework** | Vitest 3.1.1 (jsdom, globals) + `@vue/test-utils`; Playwright 1.58.2 for the perf harness only |
| **Config file** | `neode-ui/vitest.config.ts` (present); `neode-ui/playwright.config.ts` (present, `ARCHY_BASE_URL` override) |
| **Quick run command** | `cd neode-ui && npm run test -- <path/to/file>.test.ts` |
| **Full suite command** | `cd neode-ui && npm run test` (`vitest run`) |
| **Type gate** | `cd neode-ui && npm run type-check` (`vue-tsc --noEmit`) — chained into every plan's verify |
| **Build gate** | `cd neode-ui && npm run build` (`vue-tsc -b && vite build``web/dist/neode-ui/`) — chained into the last task of plans 02-04/05/06/07 and 02-08 Task 1 |
| **Estimated runtime** | Single file ~5s · full suite ~57s (measured 2026-07-30: 84 files / 700 tests, all green) · `type-check` ~1s · build is the long pole |
All infrastructure is already installed — no framework install is required by this phase.
---
## Sampling Rate
- **After every task commit:** the task's own `<automated>` command — a targeted
`npm run test -- <touched test file>` plus `npm run type-check` (~5-10s).
- **After every plan wave:** `cd neode-ui && npm run test` (full suite, ~57s). Every plan's
final task already chains the full suite, so wave completion implies a green full run.
- **Before `/gsd-verify-work`:** full suite green **and** `02-FINDINGS.md` `## Results`
committed **and** the D-11 manual pass-bar walkthrough on archi-dev-box (02-08 Task 3).
- **Max feedback latency:** < 60s for any test-only verification; build-inclusive tasks
(02-04-02, 02-05-02, 02-06-02, 02-07-02, 02-08-01) are longer by one production build.
---
## Per-Task Verification Map
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
| 02-01-01 | 01 | 1 | PERF-01 | T-02-06, T-02-08 | Harness records RPC method names + timings only — no request/response bodies, page text or screenshots | e2e (Playwright) + tsc | `cd neode-ui && npx tsc --noEmit -p tsconfig.json 2>&1 \| grep -v 'e2e/test-results' ; npx playwright test e2e/perf/surface-perf.spec.ts --project=chromium --reporter=line` | ❌ created in-task | ⬜ pending |
| 02-01-02 | 01 | 1 | PERF-01 | T-02-06 | Baseline artifact carries timings and method names only | artifact assertion | `node -e "const r=require('.../02-PERF-BASELINE.json'); const rows=r.results??r; if(!Array.isArray(rows)\|\|rows.length===0)process.exit(1); const bad=rows.filter(x=>x.error==null&&(x.revisitMs==null\|\|x.revisitRpcCount==null)); if(bad.length){console.error('incomplete rows',bad.map(b=>b.id));process.exit(1)} console.log('rows',rows.length)"` | ❌ artifact created in-task | ⬜ pending |
| 02-01-03 | 01 | 1 | PERF-01 | T-02-06, T-02-07 | Redaction pass before commit — onion addresses, DIDs, pubkeys, wallet figures, peer hostnames, file names | doc-structure assertion | `test -f .../02-FINDINGS.md && for s in '## Method' '## Per-Surface Findings' '## Ranked Fix Order' '## Surfaces Left Alone' '## Corrections to Prior Research' '## Owning Plans'; do grep -qF "$s" .../02-FINDINGS.md \|\| { echo "missing: $s"; exit 1; }; done; echo OK` | ❌ doc created in-task | ⬜ pending |
| 02-02-01 | 02 | 2 | PERF-02 | T-02-01, T-02-02, T-02-09 | Explicit per-resource `persist` decision (not the default); no identity-bearing cache key before 02-03 lands | unit (Vitest + `@vue/test-utils`) | `cd neode-ui && npm run test -- src/views/dashboard/__tests__/keepAliveTabs.test.ts src/composables/__tests__/useCachedResource.test.ts && npm run type-check` | ❌ both created in-task (TDD RED) | ⬜ pending |
| 02-02-02 | 02 | 2 | PERF-02 | T-02-03 | Intervals/subscriptions stop on `onDeactivated`; `KEEP_ALIVE_MAX` = 6 with LRU eviction | unit + full suite | `cd neode-ui && npm run test -- src/views/dashboard/__tests__/keepAliveTabs.test.ts && npm run type-check && npm run test` | ✅ (from 02-02-01) | ⬜ pending |
| 02-02-03 | 02 | 2 | PERF-02 | — | N/A | manual (`checkpoint:human-verify`, blocking) | N/A — see Manual-Only Verifications | — | ⬜ pending |
| 02-03-01 | 03 | 2 | PERF-03 | T-02-02 | `resources.clearAll()` called from `auth.logout()` on success **and** failure paths; purges the `resource:` sessionStorage prefix | unit | `cd neode-ui && npm run test -- src/stores/__tests__/resourcesClear.test.ts && npm run type-check` | ❌ created in-task | ⬜ pending |
| 02-03-02 | 03 | 2 | PERF-03 | T-02-01, T-02-11, T-02-12 | Every key embeds the route item id (isolation asserted on rendered content); credentials/DIDs/wallet are `persist: false`; `invalidate()` on destructive-action completion | unit | `cd neode-ui && npm run test -- src/views/__tests__/secondaryScreenCache.test.ts && npm run type-check` | ❌ created in-task | ⬜ pending |
| 02-03-03 | 03 | 2 | PERF-03 | T-02-10, T-02-12 | File listings and media metadata are `persist: false` unconditionally, independent of findings classification | unit + full suite | `cd neode-ui && npm run test -- src/views/__tests__/secondaryScreenCache.test.ts && npm run test && npm run type-check` | ✅ (from 02-03-02) | ⬜ pending |
| 02-04-01 | 04 | 3 | PERF-02 | T-02-03, T-02-13, T-02-15 | Timers/subscriptions/listeners follow activation not mount; starts are idempotent (no double-arm); live-data surfaces revalidate immediately on `onActivated` | unit + full suite | `cd neode-ui && npm run test -- src/views/dashboard/__tests__/keepAliveLifecycle.test.ts && npm run test && npm run type-check` | ❌ created in-task | ⬜ pending |
| 02-04-02 | 04 | 3 | PERF-02 | T-02-14 | Exact-path matching retained; `shouldKeepAlive` asserted false for six secondary-screen paths whose prefixes match a registered tab | unit + full suite + build | `cd neode-ui && npm run test -- src/views/dashboard/__tests__/keepAliveLifecycle.test.ts src/views/dashboard/__tests__/keepAliveTabs.test.ts && npm run test && npm run type-check && npm run build` | ✅ (from 02-04-01, 02-02-01) | ⬜ pending |
| 02-04-03 | 04 | 3 | PERF-02 | T-02-03 | N/A | manual (`checkpoint:human-verify`, blocking) | N/A — see Manual-Only Verifications | — | ⬜ pending |
| 02-05-01 | 05 | 4 | PERF-02 | T-02-01, T-02-13, T-02-16 | `persist: false` on every group carrying a DID, onion address, pubkey or contact record; no per-group awaiting (overlapping start times asserted) | unit + full suite | `cd neode-ui && npm run test -- src/views/__tests__/meshTabCache.test.ts && npm run test && npm run type-check` | ❌ created in-task | ⬜ pending |
| 02-05-02 | 05 | 4 | PERF-02 | T-02-03 | D3 simulation stopped and animation frames cancelled on deactivate; exactly one simulation and one map per session | unit + full suite + build | `cd neode-ui && npm run test -- src/views/__tests__/meshTabCache.test.ts && npm run test && npm run type-check && npm run build` | ✅ (from 02-05-01) | ⬜ pending |
| 02-06-01 | 06 | 4 | PERF-02 | T-02-17, T-02-16 | RESEARCH assumption A3 settled per loader with the verdict recorded; any genuine ordering dependency kept ordered; no serialization of the fan-out | unit (+ existing regression) + full suite | `cd neode-ui && npm run test -- src/views/__tests__/serverTabCache.test.ts src/views/__tests__/ServerNetworkRefresh.test.ts && npm run test && npm run type-check` | ❌ `serverTabCache` created in-task · ✅ `ServerNetworkRefresh` exists | ⬜ pending |
| 02-06-02 | 06 | 4 | PERF-02 | T-02-01, T-02-13, T-02-16 | Wallet balances, transaction history, VPN peer identity and Tor onion addresses are `persist: false` (test-asserted); wallet revalidates unconditionally on re-entry | unit + full suite + build | `cd neode-ui && npm run test -- src/views/__tests__/homeTabCache.test.ts && npm run test && npm run type-check && npm run build` | ❌ created in-task | ⬜ pending |
| 02-07-01 | 07 | 4 | PERF-02 (D-14) | T-02-19, T-02-20 | The contract doc is the review point — no identity- or session-bearing parameter may ship in the iframe query string; deployment impact recorded under D-15 | doc-structure assertion | `D=.../02-AIUI-D14.md; test -f "$D" \|\| exit 1; for s in '## Source Location' '## Embed Parameter Contract' '## D-14a' '## D-14b' '## Deployment Impact'; do grep -qF "$s" "$D" \|\| { echo "missing: $s"; exit 1; }; done; echo OK` | ❌ doc created in-task | ⬜ pending |
| 02-07-02 | 07 | 4 | PERF-02 (D-14) | T-02-05, T-02-18 | `onAiuiMessage` origin check untouched — test asserts a foreign-origin message does not set `aiuiConnected`; flags are presentation-only, no capability/token parameter added | unit + full suite + build | `cd neode-ui && npm run test -- src/views/__tests__/chatAiuiEmbed.test.ts && npm run test && npm run type-check && npm run build` | ❌ created in-task | ⬜ pending |
| 02-07-03 | 07 | 4 | PERF-02 (D-14) | — | N/A | manual (`checkpoint:human-verify`, blocking) | N/A — see Manual-Only Verifications | — | ⬜ pending |
| 02-08-01 | 08 | 5 | PERF-01, PERF-02, PERF-03 | T-02-21, T-02-22, T-02-03 | `--frontend-only` at the dev pair only; `--tailscale`/`--tailscale-node`/OTA forbidden; built bundle greped for a string from every plan before deploy (CLAUDE.md silent-no-op rule) | build + bundle grep | `cd neode-ui && npm run type-check && npm run test && npm run build && for s in shouldKeepAlive RefreshIndicator app-catalog; do grep -rqs "$s" ../web/dist/neode-ui/ \|\| { echo "MISSING FROM BUNDLE: $s"; exit 1; }; done; echo BUNDLE_OK` | ✅ (no new test file) | ⬜ pending |
| 02-08-02 | 08 | 5 | PERF-01 | T-02-06, T-02-22 | Same redaction rule as 02-01 — method names and timings only, no addresses, identities, balances or file names; precondition re-greps the asset actually served by the node | artifact comparison + doc assertion | `node -e "const p='.../'; const a=require(p+'02-PERF-AFTER.json'), b=require(p+'02-PERF-BASELINE.json'); const ar=a.results??a, br=b.results??b; if(!Array.isArray(ar)\|\|ar.length!==br.length){console.error('row count mismatch',ar.length,br.length);process.exit(1)} console.log('rows',ar.length)" && grep -qF '## Results' .../02-FINDINGS.md && grep -qF '## Outstanding' .../02-FINDINGS.md && echo OK` | ❌ artifact created in-task | ⬜ pending |
| 02-08-03 | 08 | 5 | PERF-01, PERF-02, PERF-03 | T-02-03 | N/A | manual (`checkpoint:human-verify`, blocking — D-11 pass bar) | N/A — see Manual-Only Verifications | — | ⬜ pending |
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
*Paths abbreviated as `.../` are `.planning/phases/02-ui-performance/`; the plans carry
absolute paths. `\|` in a command cell is a literal `|`.*
*Sampling continuity: the four blocking human checkpoints (02-02-03, 02-04-03, 02-07-03,
02-08-03) are each the last task of their plan and are separated by automated tasks — no
three consecutive tasks lack an automated verify.*
---
## Wave 0 Requirements
**No separate Wave 0 plan is needed.** Vitest 3.1.1 and Playwright 1.58.2 are already
installed and configured, and every missing test file is created inside its own task's TDD
RED step rather than deferred — so no task carries a `MISSING —` placeholder.
Test/harness files this phase creates (owner task in parentheses):
- [ ] `neode-ui/e2e/perf/surfaces.ts`, `e2e/perf/measure.ts`, `e2e/perf/surface-perf.spec.ts` — perf harness (02-01-01)
- [ ] `neode-ui/src/composables/__tests__/useCachedResource.test.ts``onActivated` revalidation + no-op outside `<KeepAlive>` (02-02-01)
- [ ] `neode-ui/src/views/dashboard/__tests__/keepAliveTabs.test.ts` — instance identity across a tab round-trip (02-02-01)
- [ ] `neode-ui/src/stores/__tests__/resourcesClear.test.ts` — cache purge on logout (02-03-01)
- [ ] `neode-ui/src/views/__tests__/secondaryScreenCache.test.ts` — per-item keying, isolation, invalidation (02-03-02)
- [ ] `neode-ui/src/views/dashboard/__tests__/keepAliveLifecycle.test.ts` — activate/deactivate timers and path matching (02-04-01)
- [ ] `neode-ui/src/views/__tests__/meshTabCache.test.ts` — six-group caching without serialization (02-05-01)
- [ ] `neode-ui/src/views/__tests__/serverTabCache.test.ts` — seven Server load groups (02-06-01)
- [ ] `neode-ui/src/views/__tests__/homeTabCache.test.ts` — Home caching + wallet freshness (02-06-02)
- [ ] `neode-ui/src/views/__tests__/chatAiuiEmbed.test.ts` — stable embed URL + origin check intact (02-07-02)
Existing files reused as regression gates: `neode-ui/src/views/__tests__/ServerNetworkRefresh.test.ts`,
`neode-ui/src/stores/__tests__/resources.test.ts`.
Doc/data artifacts gating downstream waves (deliverables, not tests): `02-PERF-BASELINE.json`
and `02-FINDINGS.md` (02-01), `02-AIUI-D14.md` (02-07-01), `02-PERF-AFTER.json` (02-08-02).
---
## Manual-Only Verifications
| Behavior | Requirement | Why Manual | Test Instructions |
|----------|-------------|------------|-------------------|
| Tracer tab feels instant on revisit; subtle refresh indicator appears after TTL; secondary screens still remount; tab transition animation unchanged; offline keeps last value with no toast | PERF-02 | Perceptual — "no spinner, no blank frame, no animation replay" is a render-timing judgment no jsdom assertion reproduces | 02-02 Task 3 `<how-to-verify>` steps 17 (`./scripts/dev-start.sh`, :8100 preview against archi-dev) |
| All ten main tabs instant on revisit with in-page state preserved; Home wallet re-checks on re-entry; Chat panel does not reload; LRU eviction observable at the cap; no off-screen CPU drain | PERF-02 | Perceptual plus an idle-CPU/fan observation over several minutes — off-screen timer leakage has no deterministic unit assertion | 02-04 Task 3 `<how-to-verify>` steps 19 |
| AIUI panel persists across tab switches and survives a breakpoint resize; chat opens expanded (D-14a); mobile opens on the chat view (D-14b); the AIUI connection still works | PERF-02 (D-14) | Requires a real mobile viewport and a live AIUI connection across an iframe boundary | 02-07 Task 3 `<how-to-verify>` steps 18 |
| **D-11 pass bar** — no visible spinner or blank screen on any revisited tab or secondary screen on archi-dev-box; app store immediate after first visit; Mesh graph held; sustained under extended use | PERF-01, PERF-02, PERF-03 | The phase's own acceptance bar is an explicit on-device subjective judgment on real hardware ("is the sluggishness gone"), not a threshold | 02-08 Task 3 `<how-to-verify>` steps 110, run on the node itself against the deployed build |
| PERF-01 findings quality — each named cause is actually justified by the cited baseline field | PERF-01 | 02-01-03 automates the doc's *structure*; the *judgment* that each cause↔evidence pairing is sound is human review | Read `02-FINDINGS.md` `## Per-Surface Findings` against `02-PERF-BASELINE.json`; confirm every non-`unmeasured` row cites its justifying field |
---
## Validation Sign-Off
- [ ] All tasks have `<automated>` verify or Wave 0 dependencies
- [ ] Sampling continuity: no 3 consecutive tasks without automated verify
- [ ] Wave 0 covers all MISSING references
- [ ] No watch-mode flags
- [ ] Feedback latency < 60s
- [ ] `nyquist_compliant: true` set in frontmatter
**Approval:** pending