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

23 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, requirements-completed, coverage, duration, completed, status
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions requirements-completed coverage duration completed status
02-ui-performance 08 ui
playwright
vue3
keepalive
performance-verification
connection-pool
real-hardware
phase provides
02-ui-performance/02-01 The re-runnable surface-perf harness (neode-ui/e2e/perf/{surfaces,measure,surface-perf.spec}.ts) and the 02-PERF-BASELINE.json this plan re-runs against and compares to
phase provides
02-ui-performance/02-02..02-07 The full KeepAlive + useCachedResource architecture (all main tabs, Mesh, Server/Home, Chat/AIUI) this plan deploys and measures on real hardware
02-PERF-AFTER.json — the after-artifact from re-running the 02-01 harness unmodified against archi-dev-box
02-FINDINGS.md Results/Outstanding sections — per-surface before/after comparison, with a documented remount-probe methodology correction
KEEP_ALIVE_MAX confirmed at 6 via an on-device Chromium heap reading (FA-D closed)
A real-hardware connection-pool-starvation defect found, root-caused, and fixed in Cloud.vue (content.browse-peer unbounded fan-out)
The phase's own D-11 pass bar, human-approved on archi-dev-box
added patterns
Concurrency-capped RPC fan-out (queue + worker pool, BROWSE_PEER_CONCURRENCY=3) mirroring PeerFiles.vue's existing PREVIEW_CONCURRENCY convention — the second instance of this pattern in the codebase, now established for any per-peer/per-item RPC fan-out
Harness remount-probe correction: a generic rootSelector (.view-container) shared across every main tab becomes ambiguous once real KeepAlive keeps multiple instances alive simultaneously — verify by stamping/reading the VISIBLE match (getBoundingClientRect/offsetParent) rather than the first DOM match, since KeepAlive's inactive cached instances are not laid out on screen
CDP Performance.getMetrics (JSHeapUsedSize) as the on-device memory-reading instrument for KEEP_ALIVE_MAX tuning, more reliable across Chromium variants than performance.memory
created modified
.planning/phases/02-ui-performance/02-PERF-AFTER.json
.planning/phases/02-ui-performance/02-FINDINGS.md
neode-ui/src/views/dashboard/keepAliveRoutes.ts
neode-ui/src/views/Cloud.vue
KEEP_ALIVE_MAX left at 6, now backed by measurement instead of estimate: 4 full two-way cycles through all 11 main tabs on archi-dev-box showed JS heap fluctuating 10-21MB with no monotonic growth trend, confirming the cap's eviction genuinely bounds memory rather than sitting unused against the 10 registered cache-eligible paths
Deployed to archi-dev-box only (this machine, confirmed via Tailscale MagicDNS to be the same physical ThinkPad build server) — archy-x250-dev, the dev pair's second node, was offline for the entire plan (checked at Task 1, before Task 2, and again before the final redeploy; never came back). D-11's verification target is archi-dev-box specifically, so this satisfies the plan, but the second dev-pair node has received none of this phase's changes and needs the same --frontend-only deploy once it's reachable
The harness's own remount-probe field is confounded for main tabs once real KeepAlive caching is active (multiple .view-container-classed instances coexist; document.querySelector's first-DOM-match can read/write the wrong one) — corrected independently via a harness-external, reproduced-twice verification rather than editing the frozen 02-01 harness; Home/Apps/Marketplace/Cloud/Web5/Fleet confirmed to genuinely survive a round-trip, Server confirmed to genuinely NOT (a real, open gap)
A user-reported checkpoint regression (first visit to Cloud: no folder opens on click) was treated as a release-blocking defect, not a known-open item, per explicit coordinator direction — required two separate fix commits to fully close: a fresh-mount guard (necessary but insufficient) and a concurrency cap + timeout on content.browse-peer's per-peer fan-out (the actual mechanism: 13 of 14 concurrent RPCs to dead/unreachable peers never settled, starving Chromium's per-origin connection pool and silently breaking every subsequent same-origin fetch including lazy route-chunk imports)
Four other user-reported UX issues (Paid Files opening in a new tab instead of the lightbox, PiP not closing the lightbox, a missing loader state on Paid Files' item-open RPC, PiP not surviving tab changes/buffering) were classified via git history against the pre-phase-2 baseline commit (a75b6709) and confirmed pre-existing, not phase-2 regressions — captured with file/line pointers into UIFIX-04/05/06 rather than fixed here, per the phase's own scope boundary and explicit coordinator direction not to implement fixes for pre-existing gaps
PERF-01
PERF-02
PERF-03
id description requirement verification human_judgment
D1 The 02-01 harness re-run unmodified against archi-dev-box produces a directly comparable after-artifact (02-PERF-AFTER.json), 15/15 rows matching the baseline's row count PERF-01
kind ref status
automated_ui neode-ui/e2e/perf/surface-perf.spec.ts run against http://archi-dev-box, ARCHY_PERF_RUNS=3 — exit code 0, 15/15 rows written pass
false
id description requirement verification human_judgment
D2 Every surface named as slow in the findings has a committed after-number and Verdict (improved/unchanged/regressed/unmeasured); no regression or unmeasured surface is averaged away or hidden PERF-01
kind ref status
other 02-FINDINGS.md ## Results table (15 rows, every Verdict cell populated) and ## Outstanding (every regression/gap explicitly listed) pass
false
id description requirement verification human_judgment
D3 Every main tab registered in KEEP_ALIVE_PATHS is independently re-verified for genuine instance survival across a tab round-trip, correcting a harness-methodology confound discovered this run PERF-02
kind ref status
other 02-FINDINGS.md Results section — corrected remount verification reproduced twice per surface (Home/Apps/Marketplace/Cloud/Web5/Fleet survive; Server does not, recorded as an open gap, not hidden) pass
false
id description requirement verification human_judgment
D4 KEEP_ALIVE_MAX is set from an observed on-device memory reading rather than an estimate, with the reading recorded PERF-02
kind ref status
other neode-ui/src/views/dashboard/keepAliveRoutes.ts comment (4 cycles, 11 tabs, CDP JSHeapUsedSize: 8.8MB baseline, 10.02/20.69/16.67/14.12MB per cycle, no monotonic growth) pass
false
id description requirement verification human_judgment rationale
D5 The D-11 pass bar (no visible spinner/blank on revisit of an already-visited tab or secondary screen this session) is confirmed on archi-dev-box by a human, on real node hardware — including a real, user-reported regression found during the check being root-caused and fixed rather than shipped as known-open PERF-03
kind ref status
manual_procedural Task 3 checkpoint:human-verify — first pass 'otherwise it's getting much better' plus 4 specific issues; the one release-blocking issue (Cloud first-visit folder-click) was fixed across two commits and the user's final re-check on archi-dev-box returned 'approved' pass
true Visual/perceptual confirmation of no-spinner/no-blank revisits and of the fix's real-world feel is inherently a human judgment call a script cannot make, consistent with every prior plan's D-11 checkpoint precedent in this phase.
~3h10min (includes one human-action checkpoint pause for the archi-dev-box credential, one human-verify checkpoint round-trip with two follow-up investigation/fix cycles) 2026-07-30 complete

Phase 02 Plan 08: Dev-Pair Deploy, On-Device Re-Measure, D-11 Pass Bar Summary

Deployed the full phase to archi-dev-box, re-measured every surface with the same harness and target as the baseline (uncovering and correcting a remount-probe confound the new KeepAlive architecture exposed), confirmed KEEP_ALIVE_MAX=6 from an on-device memory reading, and closed a real first-visit connection-pool-starvation regression found during the human pass bar — content.browse-peer's unbounded, untimed per-peer fan-out, not the router or the click handler.

Performance

  • Duration: ~3h10min (Task 1 build+deploy+memory-tuning, a human-action checkpoint pause for the archi-dev-box password, Task 2 re-measurement, and a Task 3 checkpoint round-trip with two full investigation-and-fix cycles for a user-reported regression)
  • Completed: 2026-07-30
  • Tasks: 3/3 completed (Task 3 is the plan's checkpoint:human-verify, approved)
  • Files modified: 3 (1 artifact created, 2 source files modified across 6 substantive commits)

Accomplishments

  • Deployed this phase's frontend (and confirmed AIUI's already-current development-branch build) to archi-dev-box via ARCHIPELAGO_TARGET=archipelago@archi-dev-box scripts/deploy-to-target.sh --frontend-only — this machine (the ThinkPad build server) is archi-dev-box itself, confirmed via Tailscale MagicDNS. archy-x250-dev, the dev pair's second node, was checked and found offline at three separate points across the plan and never came back; only archi-dev-box received this phase's build, which is what D-11 names as the verification target.
  • Confirmed the built bundle was genuinely current (not a stale/no-op build) by grepping the served asset (/opt/archipelago/web-ui, not just the local web/dist copy) for representative strings from every plan in the phase.
  • Tuned KEEP_ALIVE_MAX from a real on-device Chromium heap reading (CDP Performance.getMetrics) instead of leaving the carried-forward estimate unexamined: 4 full two-way cycles through all 11 main tabs showed the heap fluctuating 10-21MB with no monotonic growth — confirmed the cap at 6 is genuinely bounding memory, not sitting unused. Left unchanged, now measurement-backed.
  • Re-ran the plan 02-01 harness unmodified against archi-dev-box, producing 02-PERF-AFTER.json (15/15 rows, matching the baseline's row count) and appending 02-FINDINGS.md's ## Results/## Outstanding sections.
  • Discovered and corrected a harness-methodology confound this run exposed for the first time: the remount probe's generic .view-container selector — unambiguous pre-phase-2 when only one view was ever mounted — becomes ambiguous once real KeepAlive keeps multiple main-tab instances alive simultaneously. Rather than editing the frozen harness, independently re-verified every main tab's true remount status with a corrected, reproduced-twice method: Home/Apps/Marketplace/Cloud/Web5/Fleet genuinely survive a round-trip; Server genuinely does not — recorded as an open, unfixed gap rather than smoothed over.
  • Recorded real timing regressions (Discover, Server, Web5, Fleet, AppDetails, OpenWrtGateway) honestly per the plan's own prohibition against averaging them away, with a same-time-of-day-variance caveat noted for interpretation, not used to soften any verdict.
  • Found, root-caused, and fixed a genuine real-hardware regression during the Task 3 checkpoint: a user-reported "first visit to Cloud, no folder opens on click" was proven — via direct instrumentation (a raw DOM click listener, a patched live $router instance, request-lifecycle tracking, and manual import() calls from the page console) — to be a downstream symptom of Chromium's per-origin connection pool being starved by 13 of 14 concurrent, permanently-pending content.browse-peer RPCs to dead/unreachable peers, not a router or click-handler bug. Closed across two commits: a fresh-mount guard on Cloud.vue's dual onMounted/onActivated fire (necessary but insufficient alone), then a concurrency cap (3) + shortened timeout (10s) on the peer-browse fan-out itself, mirroring PeerFiles.vue's existing PREVIEW_CONCURRENCY pattern. Verified 5/5 fresh sessions navigate cleanly, zero in-flight hung requests after 15s on Cloud, and a previously-permanently-hung route chunk import now resolves in 17ms. User's final on-node re-check: approved.
  • Classified four other user-reported UX issues via git history against the pre-phase-2 baseline commit (a75b6709) and confirmed all pre-existing, not phase-2 regressions, with exact file/line pointers captured into UIFIX-04/05/06 for phase 1's gap-closure work — no fixes implemented for these, per scope boundary and explicit direction.

Task Commits

Each task was committed atomically (Task 3's checkpoint follow-up investigation produced additional fix/docs commits, listed under it):

  1. Task 1: Build and deploy the frontend to the dev pair only - 3ee20430 (docs — KEEP_ALIVE_MAX confirmed via on-device memory reading; no code change needed since the constant stayed at 6)
  2. Task 2: Re-measure on archi-dev-box and write the before/after comparison - f1206ad6 (docs — 02-PERF-AFTER.json + FINDINGS.md Results/Outstanding)
  3. Task 3: D-11 pass bar checkpoint - checkpoint:human-verify, first pass returned "otherwise it's getting much better" plus 4 specific issues; investigation and fixes landed as:
    • e1a3f31a (fix — Cloud.vue fresh-mount guard; necessary, not sufficient alone)
    • 834edd8c (docs — checkpoint follow-up: triage of all 5 reported items, root cause instrumentation findings)
    • 8fe6217b (fix — content.browse-peer concurrency cap + timeout; the fix that actually closed the regression)
    • a0c58277 (docs — confirmation the fix is verified 5/5, mechanism closed)
    • Final on-node re-check: approved

Plan metadata: (this commit) - docs(02-08): complete dev-pair deploy, on-device re-measure, D-11 pass bar plan

Files Created/Modified

  • .planning/phases/02-ui-performance/02-PERF-AFTER.json - After-artifact from re-running the 02-01 harness against archi-dev-box (15 rows, commit: "3ee20430", runs: 3)
  • .planning/phases/02-ui-performance/02-FINDINGS.md - ## Results (per-surface baseline/after comparison + corrected remount verification), ## Outstanding (every regression/gap/carried assumption), and a ## Addendum: Task 3 Checkpoint Follow-Up documenting the full investigation and classification of all 5 user-reported items
  • neode-ui/src/views/dashboard/keepAliveRoutes.ts - KEEP_ALIVE_MAX comment updated to record the on-device memory reading that justifies leaving it at 6 (FA-D closed)
  • neode-ui/src/views/Cloud.vue - Fresh-mount guard on syncOnEntry() (matching Home/Web5/Mesh/Server's existing pattern) + content.browse-peer fan-out capped at 3 concurrent with a 10s per-call timeout (BROWSE_PEER_CONCURRENCY, BROWSE_PEER_TIMEOUT_MS, a queue/worker pool mirroring PeerFiles.vue's PREVIEW_CONCURRENCY convention)

Decisions Made

See key-decisions in frontmatter for the full list. Highlights:

  • KEEP_ALIVE_MAX stays 6, now backed by a real on-device memory reading rather than the carried-forward FA-D estimate.
  • archi-dev-box onlyarchy-x250-dev was offline for the plan's entire duration (checked three times); recorded honestly rather than silently skipped, per D-11's specific naming of archi-dev-box as the verification target.
  • The harness's remount-probe field is unreliable for main tabs post-KeepAlive — corrected via an independent, reproduced-twice verification method rather than editing the frozen 02-01 harness; the correction revealed Server.vue's genuine remount gap, which the raw (confounded) field would have hidden as "unchanged."
  • The Cloud first-visit regression was treated as release-blocking, not known-open, per explicit coordinator direction — required isolating the true mechanism (an unbounded, untimed RPC fan-out to dead peers starving the browser's connection pool) rather than stopping at the first plausible-looking fix (the fresh-mount guard alone did not resolve it, and was honestly reported as insufficient before the real fix was found).
  • Pre-existing UX issues were classified, not fixed — Paid Files' window.open() instead of the lightbox, PiP not closing the lightbox, a missing loader state on Paid Files' item-open, and PiP not surviving tab changes/buffering were all traced to commits predating phase 2 (f3393581, f72d4b92, both 2026-07-22/23, confirmed via git merge-base --is-ancestor against the a75b6709 pre-phase-2 baseline) — captured into UIFIX-04/05/06 rather than fixed here, respecting this plan's own scope boundary.

Deviations from Plan

Auto-fixed Issues

1. [Rule 1 - Bug, caught by the D-11 checkpoint] Cloud.vue's dual onMounted/onActivated fire doubled the first-activation request burst

  • Found during: Task 3 checkpoint, user-reported "first visit to Cloud, no folder opens on click"
  • Issue: 02-04 exempted Cloud.vue from the fresh-mount guard pattern used elsewhere (Home/Web5/Mesh/Server), reasoning each individual resource is staleness/inflight-deduped. True per-resource, but the two back-to-back onMounted+onActivated passes still doubled loadPeerFiles()'s full per-peer RPC fan-out in the same tick on a component's first KeepAlive activation.
  • Fix: Added the same fresh-mount guard (cloudFreshMount) already used in Home.vue/Web5.vue/Mesh.vue/Server.vue.
  • Files modified: neode-ui/src/views/Cloud.vue
  • Verification: Full suite green (95/774); reduced but did not eliminate the reported symptom — honestly reported as insufficient before proceeding to the real fix below.
  • Committed in: e1a3f31a

2. [Rule 1 - Bug, the actual root cause] content.browse-peer's unbounded, untimed-enough fan-out starved the browser's connection pool

  • Found during: Task 3 checkpoint follow-up, after fix #1 above did not resolve the reported regression
  • Issue: Direct instrumentation (request-lifecycle tracking of every content.browse-peer call during a fresh Cloud mount) showed 13 of 14 concurrent calls never settling at all — loadPeerFiles() fanned these out with zero concurrency cap and a 30s per-call timeout. That many simultaneously-open, indefinitely-pending same-origin requests to dead/unreachable peers starved Chromium's per-origin connection pool, silently breaking every other same-origin fetch for the rest of the session, including the lazy route chunk any later folder/tab navigation needs. Confirmed not a test-harness artifact (reproduced in full Chromium, not just headless-shell) and not explained by raw concurrency alone (an artificial 30-request burst against the same endpoint, done outside Cloud.vue, completed in 179ms with zero hang).
  • Fix: Capped the fan-out at 3 concurrent requests (BROWSE_PEER_CONCURRENCY, a queue/worker pool) and shortened each call's timeout from 30s to 10s (BROWSE_PEER_TIMEOUT_MS), mirroring PeerFiles.vue's existing PREVIEW_CONCURRENCY pattern for the identical class of problem. A timed-out/failed peer already resolved silently (no throw, no toast) via resources.ts's own error-state path — confirmed unchanged.
  • Files modified: neode-ui/src/views/Cloud.vue
  • Verification: Full suite green (95/774), type-check and build clean, keepAliveTabs.test.ts structural assertions untouched. 5/5 fresh browser sessions (brand-new context each run) navigated cleanly on the first folder click against the redeployed build; zero in-flight hung requests after 15s on Cloud (previously exactly one, permanently pending); a previously-permanently-hung lazy route chunk import resolved in 17ms. User's final on-node re-check: approved.
  • Committed in: 8fe6217b

Total deviations: 2 auto-fixed (both Rule 1 — real bugs found during this plan's own verification checkpoint, not pre-existing issues out of scope, since the phase's own lifecycle changes altered when this fan-out fires and turned a latent unbounded-RPC pattern into a deterministic first-visit navigation breaker). Impact on plan: Both were necessary corrections directly implicated by this plan's own must-have truths (the D-11 pass bar) and explicit coordinator direction that a deterministic navigation breaker cannot ship as known-open. No scope creep — both fixes stayed within Cloud.vue, the file already central to this checkpoint's investigation.

Issues Encountered

  • Authentication gate on Task 1/Task 2: archi-dev-box's real UI password was needed to drive the Playwright harness and was not derivable from this environment (matching 02-01's precedent). Paused at a checkpoint:human-action; the coordinator supplied the password out-of-band, passed only via the ARCHY_PASSWORD environment variable at runtime, never written to any committed file.
  • A recurring auto-show engagement/feature-announcement modal (the same class of overlay 02-01 documented as CompanionIntroOverlay) intermittently intercepted clicks during on-device testing across this plan's Playwright-driven diagnostics; worked around per-script with a dismiss-if-present check, never touched in application code (out of this plan's scope).
  • The node's disk usage is genuinely at 85% right now, triggering a persistent HealthNotifications.vue toast that intercepted Chat's close button in this run (a different specific blocking cause than baseline's AIUI-connection-timeout reason, same "unmeasured" outcome for Chat). Flagged in FINDINGS.md as worth a follow-up fix (the toast's wrapper lacks pointer-events: none) independent of this phase.

User Setup Required

None — no external service configuration required. archi-dev-box's real UI password, used to drive on-device verification, was supplied out-of-band by the coordinator and passed only via the ARCHY_PASSWORD environment variable at runtime; it is not stored in any file in this repository.

Next Phase Readiness

  • PERF-01, PERF-02, and PERF-03 are all now genuinely complete — PERF-03 specifically required real-node-hardware verification per its own requirement text, which this plan's Task 3 checkpoint (including the regression it caught and this plan closed) provides.
  • Open, non-blocking follow-ups carried forward (all recorded in 02-FINDINGS.md's ## Outstanding, none block this phase's completion per the user's own "otherwise much better" call):
    • Server.vue does not survive a tab round-trip despite being registered in KEEP_ALIVE_PATHS — a real, confirmed gap needing a future targeted fix.
    • Timing regressions on Discover/Web5/Fleet/AppDetails/OpenWrtGateway, recorded honestly with numbers; a same-time-of-day re-run would help disambiguate real regression from environmental (85%-disk, multi-service node) noise.
    • archy-x250-dev has received none of this phase's changes — needs the same --frontend-only deploy once it's back online.
    • /dashboard/settings remains withheld from KEEP_ALIVE_PATHS (02-04's own deliberate, unaudited-risk exclusion).
    • cloudStore.navigate()'s residual TTL gap (02-03's known gap) and PeerFiles.vue's non-useCachedResource fetch pattern (02-03's own flagged correction) remain open.
    • UIFIX-04/05/06 now have exact file/line pointers for four pre-existing UX issues surfaced during this plan's checkpoint, ready for phase 1's gap-closure work.
  • No blockers for the milestone's next phase.

Phase: 02-ui-performance Completed: 2026-07-30

Self-Check: PASSED

All claimed files found on disk (02-PERF-AFTER.json, 02-FINDINGS.md, keepAliveRoutes.ts, Cloud.vue) and all claimed commits found in git history (3ee20430, f1206ad6, e1a3f31a, 834edd8c, 8fe6217b, a0c58277).