docs(02-11): plan gap closure for six confirmed timing regressions
Fleet/AppDetails/Web5/OpenWrtGateway/Server/Discover all measured slower on revisit than the pre-phase-2 baseline (02-10's three-way dispersion analysis). This plan profiles the real cause per surface before touching source (D-10), fixes what's fixable without reverting any T-02-01 persist:false decision or touching the visual/animation contract, and re-measures with the frozen harness. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
516c3bfa07
commit
ebd0afa68b
@@ -0,0 +1,214 @@
|
||||
---
|
||||
phase: 02-ui-performance
|
||||
plan: 11
|
||||
type: execute
|
||||
wave: 8
|
||||
depends_on: ["02-10"]
|
||||
files_modified:
|
||||
- .planning/phases/02-ui-performance/02-FINDINGS.md
|
||||
- .planning/phases/02-ui-performance/02-PERF-FINAL.json
|
||||
- neode-ui/e2e/perf/profile-revisit.spec.ts
|
||||
- neode-ui/src/views/web5/Web5.vue
|
||||
- neode-ui/src/views/Server.vue
|
||||
- neode-ui/src/views/Discover.vue
|
||||
- neode-ui/src/views/AppDetails.vue
|
||||
- neode-ui/src/views/server/OpenWrtGateway.vue
|
||||
- neode-ui/src/views/Fleet.vue
|
||||
- neode-ui/src/composables/useCachedResource.ts
|
||||
- neode-ui/src/views/dashboard/dashboardViewWrappers.ts
|
||||
- neode-ui/src/views/dashboard/DashboardRouterView.vue
|
||||
- neode-ui/src/composables/useControllerNav.ts
|
||||
autonomous: true
|
||||
gap_closure: true
|
||||
requirements: [PERF-02, PERF-03]
|
||||
user_setup:
|
||||
- service: archi-dev-box (the node's own UI login)
|
||||
why: "Both the diagnostic profiling pass and the final re-measure drive a real authenticated browser session against the deployed build on archi-dev-box — the same D-11 on-device target every prior perf plan in this phase used."
|
||||
env_vars:
|
||||
- name: ARCHY_PASSWORD
|
||||
source: "Supplied out-of-band by the coordinator at runtime. Passed only as an environment variable on the harness/profiling command line — never written to a file, commit, or planning artifact. Redact as [supplied] in all committed prose."
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "Before any source file changes, a real CPU/rendering profile (CDP Profiler + Tracing domains — the same underlying data DevTools' Performance panel visualizes) has been captured for each of the six surfaces' revisit window, and 02-FINDINGS.md names, per surface, WHERE the milliseconds actually go, cited to specific profile fields — not inferred from source reading alone"
|
||||
- "Fleet ends with an explicit verdict and a re-measured number, not just a root-cause guess — it is the worst specimen (330ms baseline -> 2631ms) and this plan's clearest test of whether the named cause and the fix are correct"
|
||||
- "AppDetails ends with an explicit verdict and a re-measured number"
|
||||
- "Web5 ends with an explicit verdict and a re-measured number"
|
||||
- "OpenWrtGateway ends with an explicit verdict and a re-measured number"
|
||||
- "Server ends with an explicit verdict and a re-measured number"
|
||||
- "Discover ends with an explicit verdict and a re-measured number"
|
||||
- "Every fix applied preserves the security decisions this phase already made (T-02-01 persist:false on wallet/identity keys stays false; no re-enabling sessionStorage persistence to shave milliseconds) and the visual/animation contract keepAliveTabs.test.ts pins (structural DOM-shape assertions stay green, byte-for-byte unmodified test file)"
|
||||
- "The re-measure uses the frozen 02-01 harness unmodified (git diff --stat against the harness's three core files is empty) so 02-PERF-FINAL.json stays directly comparable to BASELINE/AFTER/REMEASURE"
|
||||
- "First-paint (when a human would perceive content) is reported separately from contentSelector-visible (the harness's stricter measured field) for every surface where they diverge meaningfully, so the report doesn't overstate how bad a fixed/irreducible cost feels in practice"
|
||||
artifacts:
|
||||
- ".planning/phases/02-ui-performance/02-FINDINGS.md — new `## Client-Side Render Cost Root Cause (gap closure)` section: profiling method, per-surface evidence, named cause, fix (or irreducible-cost justification), before/after numbers"
|
||||
- ".planning/phases/02-ui-performance/02-PERF-FINAL.json — fourth on-device measurement, 5 runs/surface, against the fixed build"
|
||||
- "neode-ui/e2e/perf/profile-revisit.spec.ts — the additive CDP-profiling diagnostic script (does not touch the frozen harness files)"
|
||||
key_links:
|
||||
- "02-PERF-FINAL.json -> 02-PERF-BASELINE.json / 02-PERF-AFTER.json / 02-PERF-REMEASURE.json — joined by surface `id`, four-way comparison on `revisitMs`"
|
||||
- "Each named cause in 02-FINDINGS.md -> the specific CPU-profile/trace-event/animation-log field that supports it"
|
||||
---
|
||||
|
||||
<objective>
|
||||
Phase 02's last open item: six surfaces are measurably SLOWER on revisit than the pre-phase-2 baseline, confirmed real (not noise) by 02-10's three-way dispersion analysis — Fleet (330ms -> 2631ms, worst, ~8x), AppDetails (1204ms -> 2668ms), Web5 (566ms -> 1329ms), OpenWrtGateway (664ms -> 1460ms), Server (738ms -> 1239ms), Discover (1083ms -> 1453ms). RPC counts are flat-or-improved on all six (confirmed in 02-FINDINGS.md's three-way table) and, for Server/Web5, the component instance is independently proven (02-09) to genuinely survive the round-trip — so this is NOT network and NOT a remount. It is client-side render/reactivity cost that KeepAlive caching made visible by removing the network wait that used to hide it.
|
||||
|
||||
D-10 discipline applies to this plan as it did to every plan before it: name the measured cause — with real profiling evidence, not a plausible-sounding hypothesis — before touching any source file. 02-10 named a class ("split-signal render/reactivation cost") but did not pinpoint a mechanism per surface; that is this plan's Task 1.
|
||||
|
||||
The target is NOT "restore the old baseline" — those baselines were already poor. A revisit to a KeepAlive-cached surface shows an existing component instance with data already in memory: no mount, no fetch, no layout from scratch. Pass bar: revisit ms under 300ms. Target: under 150ms. Where a surface genuinely cannot reach that, the plan must say so with profiling evidence naming the irreducible cost, not quietly settle at baseline and call it fixed.
|
||||
|
||||
Hard constraints carried into every task below: security decisions (T-02-01 `persist:false` on wallet/identity cache keys) are non-negotiable and stay exactly as they are regardless of any timing cost they impose. No visual or animation change — `keepAliveTabs.test.ts` structurally pins the dashboard DOM shape and must stay green and byte-for-byte unmodified. Money surfaces never present cached data as live (D-05/T-02-01, unaffected by this plan's scope). Frontend-only deploy to archi-dev-box, never the fleet/OTA path.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@$HOME/.claude/gsd-core/workflows/execute-plan.md
|
||||
@$HOME/.claude/gsd-core/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<context>
|
||||
@.planning/PROJECT.md
|
||||
@.planning/ROADMAP.md
|
||||
@.planning/STATE.md
|
||||
@CLAUDE.md
|
||||
|
||||
@.planning/phases/02-ui-performance/02-VERIFICATION.md
|
||||
|
||||
Read only these parts of the large phase artifacts:
|
||||
- `.planning/phases/02-ui-performance/02-FINDINGS.md` — `## Method`, the `## Re-measurement (gap closure)` section (three-way table, per-surface verdicts, Accepted Deviations table) — this is the exact gap this plan closes.
|
||||
- `.planning/phases/02-ui-performance/02-REVIEW.md` — the CR-01 follow-up (persist-schema-migration mechanism) and the "persist is now required, not defaulted" call-site table — every fix in this plan must preserve every `persist:false` decision recorded there.
|
||||
- `.planning/phases/02-ui-performance/02-02-SUMMARY.md` and `02-04-SUMMARY.md` — the KeepAlive wrapper architecture (`DashboardRouterView.vue`/`dashboardViewWrappers.ts`) and the lifecycle-audit bucket convention (once-per-session / every-entry / only-while-visible), so any fix follows the established pattern rather than inventing a new one.
|
||||
- `neode-ui/src/composables/useCachedResource.ts`, `neode-ui/src/stores/resources.ts` — the shared caching layer every affected surface uses.
|
||||
|
||||
Do not re-read `02-PERF-BASELINE.json` / `02-PERF-AFTER.json` / `02-PERF-REMEASURE.json` in full — extract fields with `node -e`/`jq` as needed.
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Profile each surface's revisit window and name the real cause per surface</name>
|
||||
<files>neode-ui/e2e/perf/profile-revisit.spec.ts, .planning/phases/02-ui-performance/02-FINDINGS.md</files>
|
||||
<precondition>`ARCHY_PASSWORD` is exported in the environment and `curl -sS -o /dev/null -w '%{http_code}' http://archi-dev-box/` returns 2xx/3xx. If a `cargo build`/`rustc` process is active on this shared box (`pgrep -af 'cargo|rustc'`), wait for it to finish before taking ANY timed measurement — a concurrent full workspace rebuild saturates this machine's CPU and would corrupt the numbers exactly the way 02-10's three-way analysis worked to rule out.</precondition>
|
||||
<read_first>
|
||||
`neode-ui/e2e/perf/surfaces.ts` (read-only, for `navSteps`/`contentSelector`/`rootSelector` — do not modify) and `neode-ui/e2e/perf/keepalive-remount-probe.spec.ts` (the 02-09 precedent for an additive, frozen-harness-respecting diagnostic spec: login helper, click-with-guard retry pattern).
|
||||
</read_first>
|
||||
<action>
|
||||
Build (or extend, if already present from an earlier session in this plan) a standalone, additive Playwright spec — `neode-ui/e2e/perf/profile-revisit.spec.ts` — that does NOT edit `surfaces.ts`/`measure.ts`/`surface-perf.spec.ts` (confirm via `git diff --stat` against those three files before and after this task).
|
||||
|
||||
For each of the six named surfaces (Web5, Server, Discover, AppDetails, OpenWrtGateway, Fleet), reproduce the harness's own first-visit -> away -> revisit structure, then during the revisit window ONLY, capture:
|
||||
|
||||
1. A CDP `Profiler` (CPU) sample profile (`Profiler.start`/`Profiler.stop`), aggregated by self-time per function AND per deployed chunk (vendor/index/per-route chunk — production has no sourcemaps, so bucket by chunk name, not node_modules path).
|
||||
2. A CDP `Tracing` capture (categories including `disabled-by-default-devtools.timeline`) — the same data DevTools' Performance panel renders — aggregated by event name (Layout, RecalculateStyles, Paint, CompositeLayers, RunTask, TimerFire, ...) on the renderer main thread, so rendering-pipeline cost (which a bare JS CPU profile can only see as generic "(program)"/"(idle)") is visible by name.
|
||||
3. Every `setTimeout`/`requestAnimationFrame` call scheduled during the window (delay value, count) via a runtime monkey-patch, restored after read-back.
|
||||
4. Every RPC call's wall-clock start/duration during the window (method name + timing only, no bodies — T-02-06 convention).
|
||||
5. Every CSS `transitionrun`/`transitionend`/`animationstart`/`animationend` event on `document` during the window (type, property/animation name, target tag+class, elapsed time) — decisive evidence for whether a CSS transition duration (which does NOT block Playwright's `visible` check — only non-empty bounding box + not `visibility:hidden` — but DOES affect what a human perceives) is what dominates the wall clock.
|
||||
6. A first-paint timestamp independent of Playwright's own `waitFor({state:'visible'})`: a `requestAnimationFrame`-driven poll recording the instant `contentSelector` first gets a non-empty bounding box, so first-paint and content-visible can be reported as two distinct numbers.
|
||||
|
||||
Run it against archi-dev-box and capture the full output. For each surface, read the category/function/trace breakdown and name the DOMINANT real cost — do not guess from source reading alone; if the profile is ambiguous, add more instrumentation (e.g. per-component `console.time`/`performance.mark` if trace categories aren't decisive) rather than asserting a hypothesis the data doesn't support.
|
||||
|
||||
Write a new `## Client-Side Render Cost Root Cause (gap closure)` section into `02-FINDINGS.md`: one subsection per surface, citing the specific profile/trace/timer/animation-log evidence, naming the mechanism (e.g. "N ms in Layout/RecalculateStyles scaling with subtree size," "N chained rAF calls before contentSelector's bounding box is non-empty," "a debounced/every-entry `useCachedResource` `onActivated` cascade re-triggering M resources," "the navSteps chain transits another KeepAlive'd main tab whose own reactivation cost bleeds into this surface's measured window"). Commit this findings section BEFORE starting Task 2's source edits (D-10 gate — verified by commit-order, same discipline 02-01/02-09 used).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>git diff --stat 3ee20430 -- neode-ui/e2e/perf/surfaces.ts neode-ui/e2e/perf/measure.ts neode-ui/e2e/perf/surface-perf.spec.ts (must print nothing — the instrument stays frozen)</automated>
|
||||
<automated>grep -q "## Client-Side Render Cost Root Cause (gap closure)" .planning/phases/02-ui-performance/02-FINDINGS.md && for s in Web5 Server Discover AppDetails OpenWrtGateway Fleet; do grep -q "$s" .planning/phases/02-ui-performance/02-FINDINGS.md && echo "present: $s"; done</automated>
|
||||
</verify>
|
||||
<done>02-FINDINGS.md names, with cited profiling/trace evidence, the real dominant cost for each of the six surfaces' revisit-ms cost — committed before any neode-ui/src file changes in this plan.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto" tdd="true">
|
||||
<name>Task 2: Fix each surface's named cause where fixable; record irreducible-cost justification where not</name>
|
||||
<files>neode-ui/src/views/web5/Web5.vue, neode-ui/src/views/Server.vue, neode-ui/src/views/Discover.vue, neode-ui/src/views/AppDetails.vue, neode-ui/src/views/server/OpenWrtGateway.vue, neode-ui/src/views/Fleet.vue, neode-ui/src/composables/useCachedResource.ts, neode-ui/src/views/dashboard/dashboardViewWrappers.ts, neode-ui/src/views/dashboard/DashboardRouterView.vue, neode-ui/src/composables/useControllerNav.ts, .planning/phases/02-ui-performance/02-FINDINGS.md</name>
|
||||
<behavior>
|
||||
For each surface whose Task 1 evidence names a fixable client-side cost (expensive computed re-evaluation, watcher cascade, whole-subtree re-render instead of re-attach, per-row recompute, unbounded rAF/timer chain, a navSteps transit-confound that is itself measuring another tab's real cost) apply the smallest change that removes the named cost, guarded by a test that fails before the fix and passes after. Where the named cost is genuinely irreducible (e.g., the security-mandated absence of sessionStorage persistence for wallet/identity keys forcing a real re-fetch every session-boot; or a navSteps chain that legitimately must transit another main tab because Fleet has no direct sidebar entry) do not force a fix — document the irreducible cost with its profiling evidence in 02-FINDINGS.md instead, and say so plainly rather than leaving the surface unaddressed.
|
||||
</behavior>
|
||||
<action>
|
||||
Work surface by surface, smallest diff first. Do not touch a file this task doesn't need to for a given surface's fix.
|
||||
|
||||
Guardrails that apply to every fix in this task, no exceptions:
|
||||
- Never re-enable `persist: true`/sessionStorage writes on any key T-02-01/CR-01 decided must be `persist: false` (`web5.lnd-info`, `web5.networking-profits`, `server.fips-summary`, and every other key in 02-REVIEW.md's persist-decision table) — if a fix's instinct is "cache this in sessionStorage to skip the re-fetch," that instinct is wrong for these keys; find a different mechanism (e.g. in-memory-only staleness widening, avoiding redundant re-render, not adding storage).
|
||||
- Never change `keepAliveTabs.test.ts` and never change any visible layout, spacing, animation timing/easing, or transition name — run this file's existing assertions after every change in this task and treat any diff in its output as a hard stop, not a thing to update.
|
||||
- If a fix requires touching `useCachedResource.ts`, `dashboardViewWrappers.ts`, or `DashboardRouterView.vue` (shared by every KeepAlive'd surface, not just the six named here), verify the change against the FULL existing `keepAliveLifecycle.test.ts` + `keepAliveTabs.test.ts` suite, not just the affected surface's own tests — a shared-composable/host change with an unseen side effect on an unrelated tab is exactly the class of regression 02-04's own bare-mount bug demonstrated this phase.
|
||||
- If a navSteps transit-confound is Task 1's named cause for a surface (e.g. Fleet transiting Web5, OpenWrtGateway transiting Server, Discover/AppDetails transiting Apps), the fix target is the TRANSITED tab's own reactivation cost, not the destination surface — fixing Web5's reactivation cost should show up as an improvement in Fleet's measured number too; say so explicitly if that's what happens, rather than fixing the same mechanism twice under two different surface names.
|
||||
- Every fix gets a regression test in the relevant `__tests__` file (or a new one, following the `CloudPeersRefresh.test.ts`/`MarketplaceRefresh.test.ts` precedent when an existing test file's `vi.mock('vue-router')` would conflict) that fails on the pre-fix code and passes after.
|
||||
|
||||
After each surface's fix (or irreducible-cost decision) lands, append its outcome to the `## Client-Side Render Cost Root Cause (gap closure)` section in `02-FINDINGS.md`: what changed, why, the regression test that pins it, and — once Task 3's re-measure exists — the before/after number.
|
||||
|
||||
Run the full suite, `npm run type-check`, and `npm run build` (grep the built bundle for a new string introduced by at least one fix, per CLAUDE.md's silent-no-op-build caution) after all six surfaces are addressed, before moving to Task 3.
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd neode-ui && npm test 2>&1 | tail -15</automated>
|
||||
<automated>cd neode-ui && npm run type-check</automated>
|
||||
<automated>git diff --stat -- neode-ui/src/views/dashboard/__tests__/keepAliveTabs.test.ts (must print nothing — structural visual contract untouched)</automated>
|
||||
</verify>
|
||||
<done>Every one of the six surfaces has either a landed, test-covered fix or an explicit, evidence-backed irreducible-cost note in 02-FINDINGS.md. Full suite, type-check and build are green. keepAliveTabs.test.ts is byte-for-byte unmodified and still passing. No `persist:false` decision was reverted.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 3: Deploy, re-measure with the frozen harness, and write the four-way verdict</name>
|
||||
<files>.planning/phases/02-ui-performance/02-PERF-FINAL.json, .planning/phases/02-ui-performance/02-FINDINGS.md, .planning/REQUIREMENTS.md</files>
|
||||
<precondition>No `cargo`/`rustc` process is active on this shared box (`pgrep -af 'cargo|rustc'`) — re-check immediately before both the deploy and the harness run, not just once at the start of this task, since a build can start mid-task on a shared machine.</precondition>
|
||||
<action>
|
||||
Confirm the working tree's `neode-ui/src` changes from Task 2 are the ONLY uncommitted/unpushed changes about to ship — `git status --short -- neode-ui/src` should show only this plan's own files. If another session's uncommitted work is present in `neode-ui/src` at deploy time (the exact hazard 02-10 hit), stop and report it rather than deploying it alongside this plan's fix, per the deploy-safety rule carried in this plan's context.
|
||||
|
||||
Deploy frontend-only from the MAIN checkout (never a worktree — this box IS archi-dev-box over loopback, so a worktree-sourced deploy is the exact hazard that previously destroyed ~1810 tracked files): `ARCHIPELAGO_TARGET=archipelago@archi-dev-box scripts/deploy-to-target.sh --frontend-only`. Confirm the post-deploy health check and `scripts/deploy-history.log`'s new entry (`dirty=false`, the commit hash matching Task 2's last commit).
|
||||
|
||||
Re-run the frozen harness exactly as 02-10 did: `cd neode-ui && ARCHY_BASE_URL=http://archi-dev-box ARCHY_PERF_RUNS=5 ARCHY_PERF_OUT=../.planning/phases/02-ui-performance/02-PERF-FINAL.json npx playwright test e2e/perf/surface-perf.spec.ts --project=chromium --reporter=line`, with `ARCHY_PASSWORD` exported. Confirm `git diff --stat` against the three frozen harness files is still empty.
|
||||
|
||||
Build a four-way comparison (BASELINE -> AFTER -> REMEASURE -> FINAL) for all six named surfaces, dispersion (min/median/max) not bare medians, the same discipline 02-10 established. For each surface, write an explicit verdict into `02-FINDINGS.md`:
|
||||
|
||||
- **Fixed**: revisit ms at or below the pass bar (300ms) or the stretch target (150ms), with the number and the mechanism that closed the gap.
|
||||
- **Improved but not yet under the pass bar**: report the number honestly, explain the remaining gap against the profiling evidence (do not round up to "fixed").
|
||||
- **Irreducible/justified**: the profiling evidence from Task 1/2 naming exactly why (e.g. a security-mandated re-fetch cost with no persistence to shortcut it), with the number recorded as the accepted floor.
|
||||
|
||||
Report first-paint (from Task 1's independent probe, re-run once against the final build if useful for the write-up) separately from contentSelector-visible for any surface where they diverge meaningfully, so the report states plainly whether the fix also improved the human-perceived experience, not just the harness's stricter metric.
|
||||
|
||||
Update `.planning/REQUIREMENTS.md`'s PERF-02/PERF-03 rows to point at this final verdict. Commit and push (`git add` by path, Co-Authored-By trailer, `git push gitea-ai main`).
|
||||
</action>
|
||||
<verify>
|
||||
<automated>test -f .planning/phases/02-ui-performance/02-PERF-FINAL.json && node -e "const r=require('./.planning/phases/02-ui-performance/02-PERF-FINAL.json'); console.log('rows:', (r.surfaces||r.results||r).length||Object.keys(r).length, 'baseUrl:', r.baseUrl, 'runs:', r.runs)"</automated>
|
||||
<automated>git diff --stat 3ee20430 -- neode-ui/e2e/perf/surfaces.ts neode-ui/e2e/perf/measure.ts neode-ui/e2e/perf/surface-perf.spec.ts (must print nothing)</automated>
|
||||
<automated>for s in Web5 Server Discover AppDetails OpenWrtGateway Fleet; do grep -A2 "^\*\*$s" .planning/phases/02-ui-performance/02-FINDINGS.md | head -3; done</automated>
|
||||
</verify>
|
||||
<done>02-PERF-FINAL.json exists (5 runs/surface, archi-dev-box, frozen harness). Every one of the six named surfaces (Web5, Server, Discover, AppDetails, OpenWrtGateway, Fleet) has an explicit fixed/improved/irreducible verdict with a real number in 02-FINDINGS.md. REQUIREMENTS.md reflects the final state. Work is committed and pushed.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<threat_model>
|
||||
## Trust Boundaries
|
||||
|
||||
| Boundary | Description |
|
||||
|----------|-------------|
|
||||
| operator workstation -> archi-dev-box UI login | The real node password crosses this boundary at runtime to drive both the profiling script and the final re-measure |
|
||||
| profiling script -> local console output | CPU profiles / trace events / RPC method names are printed to the terminal transcript, never written to a committed artifact verbatim |
|
||||
| fixed build -> `/opt/archipelago/web-ui` on a real node | Task 3's frontend-only deploy |
|
||||
|
||||
## STRIDE Threat Register
|
||||
|
||||
| Threat ID | Category | Component | Severity | Disposition | Mitigation Plan |
|
||||
|-----------|----------|-----------|----------|-------------|-----------------|
|
||||
| T-02-11-01 | Information Disclosure | `ARCHY_PASSWORD` | high | mitigate | Environment variable only, never inlined into a committed command, never echoed into 02-FINDINGS.md or the SUMMARY. |
|
||||
| T-02-11-02 | Information Disclosure | `profile-revisit.spec.ts` output | medium | mitigate | RPC tracking captures method name + timing only, no bodies (matches the frozen harness's own T-02-06 mitigation exactly). |
|
||||
| T-02-11-03 | Tampering | any `persist:false` cache-key decision (T-02-01/CR-01) | critical | mitigate | Task 2's guardrails explicitly forbid re-enabling sessionStorage persistence on any wallet/identity key to shave milliseconds; every fix is checked against 02-REVIEW.md's persist-decision table before landing. |
|
||||
| T-02-11-04 | Tampering | `keepAliveTabs.test.ts` (visual/structural contract) | high | mitigate | Task 2 explicitly gates every fix against this file's unmodified assertions passing; `git diff --stat` on this specific file is a Task 2 verify step. |
|
||||
| T-02-11-05 | Tampering | frozen harness (`surfaces.ts`/`measure.ts`/`surface-perf.spec.ts`) | medium | mitigate | `git diff --stat` gate in Task 1 and Task 3, identical to every prior gap-closure plan this phase. |
|
||||
| T-02-11-06 | Tampering | `scripts/deploy-to-target.sh --frontend-only` | medium | mitigate | Main-checkout only (never a worktree — this box is archi-dev-box itself), archi-dev-box only, no OTA/fleet path, post-deploy health check and deploy-history log entry confirmed. |
|
||||
| T-02-11-SC | Tampering | npm/pip/cargo installs | high | accept | No new package-manager dependency is needed for a CDP-profiling script (Playwright is already a devDependency) or for any of the named fix classes. If one becomes necessary, halt and route through the Package Legitimacy Gate. |
|
||||
</threat_model>
|
||||
|
||||
<verification>
|
||||
- 02-FINDINGS.md names the real, profiled cause for each of the six surfaces before any source-file change (commit-order verified).
|
||||
- Every one of the six surfaces ends with an explicit verdict: fixed (with numbers under the pass bar), improved-but-honest (with numbers and the remaining gap explained), or irreducible/justified (with the security or architectural reason named).
|
||||
- `02-PERF-FINAL.json` exists against a fresh archi-dev-box deploy, 5 runs/surface, frozen harness confirmed via `git diff --stat`.
|
||||
- Full vitest suite, type-check and build green; `keepAliveTabs.test.ts` byte-for-byte unmodified and passing.
|
||||
- No `persist:false` (T-02-01) decision reverted.
|
||||
- First-paint reported separately from contentSelector-visible wherever they diverge meaningfully.
|
||||
</verification>
|
||||
|
||||
<success_criteria>
|
||||
- The phase's last open item (six confirmed-real timing regressions, none previously fixed) is closed with real fixes where fixable and honest, evidenced irreducible-cost notes where not.
|
||||
- No surface is left at "accepted deviation, no further action" without at least one real attempt at profiling + fixing, per the objective's explicit reframing that the old baseline is not the target.
|
||||
- The visual/animation contract and every T-02-01 security decision this phase already made are provably unchanged.
|
||||
</success_criteria>
|
||||
|
||||
<output>
|
||||
Create `.planning/phases/02-ui-performance/02-11-SUMMARY.md` when done: per-surface before/after numbers across all four artifacts, first-paint vs content-visible where they diverge, what changed and why, what was deliberately left as an irreducible/justified cost, and confirmation the visual/security constraints held.
|
||||
</output>
|
||||
Reference in New Issue
Block a user