docs(02-08): checkpoint follow-up — triage 5 user-reported items
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 <noreply@anthropic.com>
This commit is contained in:
parent
bd6958255a
commit
834edd8c00
@ -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 `<Teleport to="body">` 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 `<video>` element from `document` (which would explain a
|
||||
native PiP session ending, per browser spec) was not conclusively provable from source
|
||||
reading alone. What IS provable, and settles the phase-2 question either way:
|
||||
pre-phase-2, switching tabs fully unmounted `Cloud.vue` and destroyed its video element
|
||||
outright (zero `<KeepAlive>` existed anywhere before 02-02) — a guaranteed PiP-ending
|
||||
event, strictly worse than or equal to whatever KeepAlive's deactivation does now. Phase 2
|
||||
could not have regressed "PiP survives a tab change" because that behavior never existed
|
||||
before phase 2 to regress from. **Pre-existing/never-supported, not a phase-2 regression**
|
||||
— a real UX gap worth phase 1's UIFIX-05 attention, but not something 02-04 broke.
|
||||
- **Buffering-pause part — pre-existing, and there is no custom handling to point at.**
|
||||
`MediaLightbox.vue`'s `<video>` element (~line 77-87) is a bare
|
||||
`<video controls autoplay @dblclick @error>` — grepping `pause`/`waiting`/`stalled` across
|
||||
`MediaLightbox.vue` and `useAudioPlayer.ts` finds zero listeners on the video element for
|
||||
those events. There is no app-level rebuffering/PiP-continuity logic to have regressed;
|
||||
PiP-during-rebuffer behavior here is entirely native browser/HTML5-video default behavior,
|
||||
untouched by any app code in any phase. **Pre-existing (by absence), not phase 2.**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user