From f17a8056541f46c6e1c6dc688b0d194bc8108733 Mon Sep 17 00:00:00 2001 From: archipelago Date: Thu, 30 Jul 2026 04:56:54 -0400 Subject: [PATCH] docs(02): resolve research open questions and backfill validation strategy --- .../phases/02-ui-performance/02-RESEARCH.md | 16 +++- .../phases/02-ui-performance/02-VALIDATION.md | 94 +++++++++++++++---- 2 files changed, 90 insertions(+), 20 deletions(-) diff --git a/.planning/phases/02-ui-performance/02-RESEARCH.md b/.planning/phases/02-ui-performance/02-RESEARCH.md index a083f15a..2b3f3dcd 100644 --- a/.planning/phases/02-ui-performance/02-RESEARCH.md +++ b/.planning/phases/02-ui-performance/02-RESEARCH.md @@ -548,7 +548,21 @@ gap between an already-modern pattern (used in 8 views) and the views that preda it's a missing-dependency finding (verified via filesystem check), not a training-data guess. -## Open Questions +## Open Questions (RESOLVED) + +Both questions below were carried into planning and are operationally resolved by the +phase plan set — resolution is a plan mechanism, not a research answer: + +- **Q1 (AIUI source/param support) → resolved by `02-07-PLAN.md` Task 1**, which searches + for the checkout (including the `.116` build server), records the embed-parameter + contract in `02-AIUI-D14.md`, and gates Task 2 behind a `` that halts the + plan if `## Source Location` records the search as exhausted — D-14 blocks rather than + silently shrinks. +- **Q2 (profiling methodology/output format) → resolved by `02-01-PLAN.md`**, whose Task 1 + builds a re-runnable Playwright harness emitting `02-PERF-BASELINE.json` and whose Task 3 + requires a `## Method` section in `02-FINDINGS.md` naming target, harness path, run + command, sample count and field meanings, with every non-`unmeasured` row citing the + baseline field that justifies its cause. 1. **Where does the AIUI source actually live, and does it already support the D-14 query-param-style controls?** diff --git a/.planning/phases/02-ui-performance/02-VALIDATION.md b/.planning/phases/02-ui-performance/02-VALIDATION.md index 96dbe3b5..de18797e 100644 --- a/.planning/phases/02-ui-performance/02-VALIDATION.md +++ b/.planning/phases/02-ui-performance/02-VALIDATION.md @@ -12,6 +12,7 @@ created: 2026-07-30 # Phase 2 — Validation Strategy > Per-phase validation contract for feedback sampling during execution. +> Backfilled from the 8 plans' actual `` blocks (02-01 … 02-08). --- @@ -19,20 +20,28 @@ created: 2026-07-30 | Property | Value | |----------|-------| -| **Framework** | {pytest 7.x / jest 29.x / vitest / go test / other} | -| **Config file** | {path or "none — Wave 0 installs"} | -| **Quick run command** | `{quick command}` | -| **Full suite command** | `{full command}` | -| **Estimated runtime** | ~{N} seconds | +| **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 -- .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:** Run `{quick run command}` -- **After every plan wave:** Run `{full suite command}` -- **Before `/gsd-verify-work`:** Full suite must be green -- **Max feedback latency:** {N} seconds +- **After every task commit:** the task's own `` command — a targeted + `npm run test -- ` 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. --- @@ -40,19 +49,64 @@ created: 2026-07-30 | Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status | |---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------| -| {N}-01-01 | 01 | 1 | REQ-{XX} | T-{N}-01 / — | {expected secure behavior or "N/A"} | unit | `{command}` | ✅ / ❌ W0 | ⬜ pending | +| 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 -- [ ] `{tests/test_file.py}` — stubs for REQ-{XX} -- [ ] `{tests/conftest.py}` — shared fixtures -- [ ] `{framework install}` — if no framework detected +**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. -*If none: "Existing infrastructure covers all phase requirements."* +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 `` (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). --- @@ -60,9 +114,11 @@ created: 2026-07-30 | Behavior | Requirement | Why Manual | Test Instructions | |----------|-------------|------------|-------------------| -| {behavior} | REQ-{XX} | {reason} | {steps} | - -*If none: "All phase behaviors have automated verification."* +| 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 `` steps 1–7 (`./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 `` steps 1–9 | +| 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 `` steps 1–8 | +| **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 `` steps 1–10, 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 | --- @@ -72,7 +128,7 @@ created: 2026-07-30 - [ ] Sampling continuity: no 3 consecutive tasks without automated verify - [ ] Wave 0 covers all MISSING references - [ ] No watch-mode flags -- [ ] Feedback latency < {N}s +- [ ] Feedback latency < 60s - [ ] `nyquist_compliant: true` set in frontmatter -**Approval:** {pending / approved YYYY-MM-DD} +**Approval:** pending