--- phase: 01-federation-mesh-hardening plan: 12 subsystem: ui tags: [vue, tailwind, flexbox, css-grid, web5, scroll] requires: - phase: 01-federation-mesh-hardening provides: "Web5.vue's existing xl:grid-cols-2 row layout and Web5ConnectedNodes.vue's tabbed card (quick task 260729-je5 made the list fill the card's height; this plan adds the missing other half)" provides: - "A bounded, sibling-matched scroll contract on Web5ConnectedNodes.vue's three tab panes (trusted/observers/requests), pinned by a structural vitest suite" - "Settled verdict on the second 'connected nodes' surface flagged by the originating todo: AccountInfoSection.vue's hits are changelog prose describing the feature, not a second scrolling list — no fix needed there" affects: [web5, federation-mesh-hardening] tech-stack: added: [] patterns: - "Sibling-matched equal-height row + inner-scroll: give the growing child `xl:flex-1 xl:basis-0` (zero flex-basis so it contributes no intrinsic height) instead of `flex-auto`/no-basis, so a CSS Grid row's default `align-items: stretch` sizes the card by its sibling, and the pane's own overflow-y-auto scrolls inside the leftover height. Card root needs `min-h-0` for the flex column to be allowed to shrink below content height, plus a row-breakpoint `xl:min-h-[Nrem]` floor for the case where the sibling itself is short." key-files: created: - neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts modified: - neode-ui/src/views/web5/Web5ConnectedNodes.vue key-decisions: - "Row-breakpoint height floor set to xl:min-h-[40rem] (not the planner's initial 20rem guess) — confirmed via Dorian's live-browser check: with node discovery disabled, Web5NodeVisibility (the row sibling) renders short, the floor takes over, and 20rem looked stunted; he asked for double, i.e. 40rem." - "Settings 'connected nodes' surface (AccountInfoSection.vue) is unrelated to this defect — its 10 'connected' hits are all changelog/what's-new prose describing the Connected Nodes feature by name, not a second scrolling list component. No code change made there." - "Live-browser verification for wide (>=1280px xl breakpoint, sibling-height match + forced-overflow scroll) and narrow (<1280px, stacked layout unchanged) viewports was performed by Dorian directly on his own already-running dev session, not by the executor — the executor does not touch :8100/:5173/:5175/:5959/:3141 (a hard constraint clarified mid-execution to mean 'never kill/restart/disturb', not 'never read from')." requirements-completed: [UIFIX-02] coverage: - id: D1 description: "The connected-nodes card's height at the xl (row) breakpoint tracks its Web5NodeVisibility sibling via CSS Grid stretch + a zero-basis flex child, instead of growing to fit every row" requirement: "UIFIX-02" verification: - kind: unit ref: "neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts#gives all three tab panes the bounded, sibling-matched scroll contract" status: pass - kind: manual_procedural ref: "Dorian's direct visual check on his running :8100 session, wide viewport — reported 'we are good' for height match, scroll, and stacked layout" status: pass human_judgment: false - id: D2 description: "The inner list scrolls within the matched height rather than growing scroll-free, for all three tabs (trusted/observers/requests)" requirement: "UIFIX-02" verification: - kind: unit ref: "neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts#gives all three tab panes the bounded, sibling-matched scroll contract" status: pass - kind: manual_procedural ref: "Dorian's direct visual check — scroll behaviour confirmed correct" status: pass human_judgment: false - id: D3 description: "A short sibling (discovery disabled) still leaves a usable list height via the xl:min-h-[40rem] floor, rather than collapsing to header+tabs" requirement: "UIFIX-02" verification: - kind: unit ref: "neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts#gives the card root a min-h-0 flex column with a row-breakpoint height floor" status: pass - kind: manual_procedural ref: "Dorian's direct feedback ('too short when discovery is disabled, should be twice as tall') drove the 20rem -> 40rem correction, applied and re-verified" status: pass human_judgment: false - id: D4 description: "The stacked (below-xl) single-column layout is byte-identical to before: same capped max-h-72 height, same scroll" requirement: "UIFIX-02" verification: - kind: unit ref: "neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts (max-h-72 asserted on all three panes; git diff confirms Web5.vue untouched and no script-block change)" status: pass - kind: manual_procedural ref: "Dorian's direct visual check, narrow viewport — stacked layout confirmed unchanged" status: pass human_judgment: false - id: D5 description: "The zero-node/empty-list edge case still renders the existing empty/loading row and the pane stays in the tree (does not collapse)" requirement: "UIFIX-02" verification: - kind: unit ref: "neode-ui/src/views/web5/__tests__/Web5ConnectedNodesScroll.test.ts#still renders the empty-state row for each pane when the node list is empty" status: pass human_judgment: false - id: D6 description: "The second 'connected nodes' surface flagged by the originating todo (settings AccountInfoSection.vue) is investigated and given an explicit verdict rather than silently skipped" verification: - kind: other ref: "grep -n -i connected neode-ui/src/views/settings/AccountInfoSection.vue — all 10 hits are changelog prose, not a scrolling list" status: pass human_judgment: false duration: 105min completed: 2026-07-31 status: complete --- # Phase 1 Plan 12: Connected-Nodes Row-Matched Scroll (UIFIX-02) Summary **Gave the connected-nodes card's three tab panes a zero-basis flex-grow contract so the card's height at the row breakpoint comes from its `Web5NodeVisibility` sibling via Grid's default stretch, with the list scrolling inside that height instead of growing to fit every row — floor tuned to 40rem per Dorian's live-browser feedback.** ## Performance - **Duration:** ~105 min (across two work sessions, separated by a live-browser verification checkpoint) - **Completed:** 2026-07-31 - **Tasks:** 2/2 (Task 2's dev-preview portion completed by Dorian directly, not the executor — see Deviations) - **Files modified:** 2 (1 component, 1 new test file) ## Accomplishments - All three tab panes (trusted/observers/requests) in `Web5ConnectedNodes.vue` now carry `min-h-0 overflow-y-auto max-h-72 xl:flex-1 xl:basis-0 xl:max-h-none` — below the `xl` breakpoint nothing changed (same cap, same scroll); at `xl` the pane contributes zero intrinsic height, so the grid row is sized by the sibling alone and the pane scrolls inside the leftover height. - Card root gained `min-h-0 xl:min-h-[40rem]` so a short sibling (e.g. discovery disabled, `Web5NodeVisibility` renders small) still leaves a full, usable list area instead of collapsing to the header+tabs strip. - New structural test `Web5ConnectedNodesScroll.test.ts` pins this contract (3 tests) so a future cleanup cannot regress it a third time (the todo notes this was already a regression of an earlier fix). - Settled the ambiguity the originating todo explicitly flagged: the "connected nodes" hits in `settings/AccountInfoSection.vue` are changelog prose describing the feature by name, not a second scrolling list — confirmed by direct grep of all 10 hits, no code change needed there. - Live-browser verification (sibling-height match at wide viewport, forced-overflow internal scroll, unchanged stacked layout at narrow viewport) was performed by Dorian on his own running `:8100` dev session rather than by the executor spinning up a competing instance. ## Task Commits Each task was committed atomically, across two rounds (the second correcting the height floor per live feedback): 1. **Task 1: End-to-end — the trusted pane scrolls at a sibling-matched height** - `ceafbcb5` (fix) — added the scroll contract classes + wrote the pinning test (initial floor: `xl:min-h-[20rem]`, the planner's flagged judgement call) 2. **Task 2 correction: raise the height floor to 40rem** - `b5628d96` (fix) — Dorian verified height-match/scroll/stacked-layout were all correct on his own running session but reported the floor was too short with discovery disabled ("should be twice as tall"); floor changed `20rem` → `40rem`, test's expected value updated to match Both commits pushed to `gitea-ai main`. No separate plan-metadata commit was needed beyond this SUMMARY's own final commit (below). _Note: this plan's Task 1 was `type="tracer" tdd="true"` — test file written first (RED verified analytically via `git diff` showing the exact classes the test's `toContain`/`not.toContain` assertions depend on), then the fix applied and the test confirmed green (GREEN)._ ## Files Created/Modified - `neode-ui/src/views/web5/Web5ConnectedNodes.vue` - card root: `min-h-0 xl:min-h-[40rem]`; all three tab panes: `xl:flex-1 xl:basis-0 xl:max-h-none` replacing `flex-auto`/no-basis, keeping `min-h-0 overflow-y-auto max-h-72` unchanged. No script-block, header, tab-strip, row-markup, or `Web5.vue` changes (verified via `git diff --stat` showing zero change to `Web5.vue`, and zero `