From 834edd8c00a73a0f0785b8240c5883e632a41345 Mon Sep 17 00:00:00 2001 From: archipelago Date: Thu, 30 Jul 2026 23:23:53 -0400 Subject: [PATCH] =?UTF-8?q?docs(02-08):=20checkpoint=20follow-up=20?= =?UTF-8?q?=E2=80=94=20triage=205=20user-reported=20items?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a Task 3 checkpoint follow-up addendum to FINDINGS.md documenting the investigation behind the fix(02-08) commit (Cloud.vue fresh-mount guard for the first-visit connection-pool stall — confirmed real, partially fixed, not yet fully resolved) plus classification of four other user-reported items, all traced via git history against the a75b6709 pre-phase-2 baseline and confirmed pre-existing (not phase 2): Paid Files opening images in a new tab instead of the lightbox, PiP not closing the lightbox, missing loader state on Paid Files' item-open RPC, and PiP not surviving tab changes/buffering pauses. No fixes applied for the pre-existing items per standing direction (captured separately as phase-1 UX work). Co-Authored-By: Claude Fable 5 --- .../phases/02-ui-performance/02-FINDINGS.md | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/.planning/phases/02-ui-performance/02-FINDINGS.md b/.planning/phases/02-ui-performance/02-FINDINGS.md index d37eb1dc..87b87252 100644 --- a/.planning/phases/02-ui-performance/02-FINDINGS.md +++ b/.planning/phases/02-ui-performance/02-FINDINGS.md @@ -316,3 +316,123 @@ is this corrected reading; the **"Remounted (raw)"** column is the harness artif (`KEEP_ALIVE_MAX`) was settled in Task 1 (see its SUMMARY — confirmed at 6 via an on-device memory reading). FA-B (`ContainerAppDetails.vue`) — see the dead-code note above. FA-E (AIUI source) — settled by 02-07 (source located, D-14 landed upstream). + +## Addendum: Task 3 Checkpoint Follow-Up (2026-07-31, post-first-pass) + +The user's first Task 3 pass reported "otherwise it's getting much better" plus four specific +issues. Each was investigated on archi-dev-box directly (not guessed), root-caused via git +history, and — where it traced to a phase-2 commit — fixed. No new plan was created per +standing direction; this addendum records the investigation and its outcome. + +### Real-node phase-2 regression: first visit to Cloud, no folder opened on click + +**Confirmed, root-caused, partially fixed, not yet fully resolved.** Reproduced deterministically +on archi-dev-box (both `chrome-headless-shell` and full Chromium — not a test-harness artifact) +with a genuinely fresh session. + +- The reported symptom ("clicking a folder does nothing") is a **downstream effect**, not a + click or router bug. Direct instrumentation proved: the click event fires (confirmed via a + raw DOM listener attached to the exact clicked node), `router.push({name:'cloud-folder',...})` + is called (confirmed by patching the live `$router` instance), but the returned promise never + settles — because Vue Router awaits the target route's async component, and that dynamic + `import()` itself never resolves. +- Confirmed via manual `import()` calls from the page console: after visiting Cloud once, importing + **any** lazy route chunk (Fleet, CloudFolder, AppDetails — unrelated views) hangs identically; + before ever visiting Cloud, the same imports resolve in ~300ms. Not chunk-specific. +- Traced to exactly one permanently-pending network request: `GET /app/filebrowser/api/resources/Photos`, + fired from `Cloud.vue`'s `fetchCounts()` on mount. Confirmed hung via request-lifecycle + tracking (`request` fires, neither `requestfinished` nor `requestfailed` ever fires, still + pending after 10s). The **identical** request, issued manually with a fresh token completely + outside of Cloud.vue, returns in 29ms — ruling out File Browser or the network path itself. + Once that one request is stuck, Chromium's per-origin connection pool appears to starve every + other same-origin fetch for the rest of the session, including the lazy chunks any later + navigation needs. +- **Fix applied** (`fix(02-08)`, commit `e1a3f31a`, `neode-ui/src/views/Cloud.vue`): gave + `Cloud.vue`'s `syncOnEntry()` the same fresh-mount guard already used in + `Home.vue`/`Web5.vue`/`Mesh.vue`/`Server.vue` (02-04 exempted Cloud on the 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 + `content.browse-peer` fan-out in the same tick, stacking on whatever else was mounting at the + same first-activation instant). Tested (95 files/774 tests green, type-check and build clean), + committed, pushed, redeployed to archi-dev-box the same way as Task 1. +- **This fix reduces one genuine, real defect but did NOT fully resolve the reported symptom** — + re-reproduced deterministically (5/5 fresh sessions) against the redeployed, fixed build. + Ruled out via direct testing before concluding this: not a `chrome-headless-shell`-only + artifact (reproduces in full Chromium too); not explained by raw request concurrency alone (an + artificial 30-concurrent-request burst against the same `/Photos` endpoint, done outside + Cloud.vue, completed in 179ms with zero hang). The precise remaining trigger was not isolated + in the time available — the next-most-likely candidate is `loadPeerFiles()`'s unbounded + `content.browse-peer` fan-out (one RPC per connected peer, fired with zero concurrency limit, + unlike `countsResource`'s own resources.ts-level inflight dedup), worth checking with a bounded + test node population and/or a request-concurrency cap. +- **This remains open.** Flagging here rather than closing it out: a genuine, reproducible, + real-hardware defect exists in Cloud.vue's first-activation request burst; the fix committed + in this plan narrows it but a further investigation/fix is still needed. Does not block this + plan's own Task 3 pass-bar judgment (the user's "otherwise much better" call already accounts + for it as a known, separately-reported issue), but should not be considered closed. + +### Classification of the other three reported issues — all pre-existing, none phase-2 + +All three traced via `git log`/`git merge-base --is-ancestor` against `a75b6709` (the commit the +02-01 baseline was taken at, i.e. the last commit before any phase-2 UI change landed). None of +the implicated files or functions were touched by any phase-2 commit; no fix was implemented for +any of these three, per standing direction (captured separately as phase-1/general UX work). + +1. **Paid Files: clicking a picture opens it in a browser tab instead of the app's lightbox.** + `neode-ui/src/views/Cloud.vue` `viewPaidItem()` (~line 470-493): for any non-audio purchased + item it does `window.open(url, '_blank', 'noopener')` on a blob URL — it never calls + `MediaLightbox.vue` (`neode-ui/src/components/cloud/MediaLightbox.vue`) at all, unlike the My + Files / Peer Files rows' `handlePreview()` paths, which do route into the lightbox. Introduced + in `f3393581` ("fix(content): double-pay is now impossible + purchases auto-file + Paid Files + tab", 2026-07-22 — confirmed an ancestor of `a75b6709` via `git merge-base --is-ancestor`). + **Pre-existing, not phase 2.** +2. **Picture-in-picture on a video doesn't close the lightbox; the transition should be fluid.** + `neode-ui/src/utils/pip.ts`'s `togglePip()` only calls + `video.requestPictureInPicture()`/`exitPictureInPicture()` — it never emits a close event or + touches `MediaLightbox.vue`'s (`neode-ui/src/components/cloud/MediaLightbox.vue`, PiP button + at ~line 21-31, `close()` at ~line 233) own visibility state, so the lightbox backdrop simply + stays open behind the PiP window with no reaction and no transition at all. Introduced in + `f72d4b92` ("feat(content): seller-picked payment methods + music always in the bottom bar + + video PiP", 2026-07-23 — zero commits touch `MediaLightbox.vue` or `pip.ts` between + `a75b6709` and `HEAD`, confirmed via `git log a75b6709..HEAD --`). + **Pre-existing, not phase 2.** +3. **Some surfaces lack loader states where an open genuinely takes time.** + Spot-checked rather than exhaustively swept (a full sweep of every secondary-screen/modal + open across the app is its own piece of work). The clearest concrete instance found: + `neode-ui/src/views/Cloud.vue` `viewPaidItem()` (same function as #1 above) makes a + `content.owned-get` RPC call with a 60-second timeout and shows **no loading indicator at + all** while it resolves — `paidLoading` (line 466) only covers the list fetch + (`content.owned-list`), not the per-item open. Clicking a Paid Files row shows nothing until + the new tab appears (or fails silently). Same commit (`f3393581`, 2026-07-22) as #1 — **pre- + existing, not phase 2**. Other candidates were not individually verified in the time + available; `CloudFolder.vue`'s native file-grid path does already show a loading skeleton + (`neode-ui/src/components/cloud/FileGrid.vue` line 4), so that one specific secondary screen + is not part of this finding. +4. **Picture-in-picture must survive tab changes or video buffering pauses; doesn't seem to.** + Two parts, classified separately: + - **Tab-change part, checked against phase 2's lifecycle changes specifically — not + implicated.** Neither `Cloud.vue`, `CloudFolder.vue`, nor `MediaLightbox.vue` + (`neode-ui/src/components/cloud/MediaLightbox.vue`) defines an `onDeactivated` hook at all + (zero matches for `onDeactivated` in any of the three) — 02-04 never touched this file and + added no teardown that pauses, resets, or unmounts video/lightbox state on tab + deactivation. `MediaLightbox` is a `` child rendered from inside + `Cloud.vue`'s template (`v-if="lightboxIndex !== null"`), so when `Cloud.vue` (KeepAlive- + cached since 02-04) deactivates on a tab switch, Vue's own KeepAlive machinery recursively + deactivates that whole subtree, including the teleported lightbox/video, moving its DOM + into KeepAlive's internal (not document-attached) storage container. Whether Vue's exact + move semantics disconnect the `