You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Problem: Scrolling in the amicode dashboard snaps back to the top on every scroll-down attempt, making content below the fold unreachable. Reported on WSL2 (linux-x64).
Approach: Three targeted fixes addressing shared patterns across all scrollable surfaces — structural equality on sessionListDirectories consumers, visibility-based loading gates, and a defensive CSS overflow fix.
Scope:session-header.tsx, session-side-panel.tsx, and home.tsx in the opencode fork overlay (fork-side edits, synced via opencode:build + sync:apply). No schema, backend, or extension-host changes.
Assumptions: The v2 layout is active (always ON for release builds). The reporter's "Development projects view" is one of the four candidate surfaces identified below — see Open question.
Context: harmoniqs.amicode v0.3.4 (linux-x64), WSL2, engine v1.18.29-amicode.26, "Development projects view in the extension UI."
Adversarial review
Reviewed manually (no amico binary). Round 1 was blocking: the original plan targeted HomeDesign in home.tsx, which is not rendered in the v2 route tree — the "/" route goes to NewSessionLanding (app.tsx:781), which redirects to a session. Round 2 re-scoped to the actual rendered surfaces and passed (approved-mechanical). Spec on disk.
Affected surface — ambiguous, four candidates
In the v2 layout, there is no standalone "home page" at "/". The reporter's "Development projects view" is one of these surfaces:
#
Surface
File
Scroll container
Rendered in v2?
S1
Sessions flyout (titlebar)
session-header.tsx:980
overflow: hidden auto, max-height 70vh
yes
S2
Side-panel "home" tab (widgets)
session-side-panel.tsx:284
overflow-y-auto on flex-1 div
yes
S3
WorkbenchPanel sidebar
workbench-panel.tsx:55
overflow-y-auto on flex-1 div
yes
S4
HomeDesign (full dashboard)
home.tsx:1078
overflow-y-auto with md:overflow-hidden parent
no
Root-cause analysis
Cause A — sessionListDirectories creates fresh arrays that cascade refetches
sessionListDirectories() (helpers.ts:69) always returns a new array. Every consumer that uses the result as a memo or query key triggers unnecessary downstream updates:
S1 (session-header.tsx:730): activeSessions memo calls sessionListDirectories on every reactive tick → new session list → <For> re-renders all rows.
S4 (home.tsx:293): projectDirectories memo passes the fresh array as a queryKey to sessionLoad → refetch → isLoading flashes true → session list unmounts → scroll resets.
Evidence:sameProjectList (home-projects.ts:126) already exists as a structural comparator for the project reconcile path.
Cause B — <Show> gates unmount content during async loading transitions
Multiple surfaces wrap scrollable content in <Show when={!loading}> gates that unmount the list on any refetch:
S1 (session-header.tsx:1070–1091): nested <Show> gates on filteredActiveSessions().length > 0.
S4 (home.tsx:1354): <Show when={!homeCardsLoading()}> unmounts the entire widget grid during resource refetch.
session-header.tsx:730 (S1): extract directories into a structurally-compared memo so the session computation only re-runs when directories actually change:
Then activeSessions reads flyoutDirectories() instead of calling sessionListDirectories inline.
Fix 2 — Prevent cards unmount on refetch (S2 and S4)
session-side-panel.tsx:285 and home.tsx:1354: replace binary <Show when={!loading}> with a visibility approach. Show skeleton only on initial load (!widgetsRaw.latest); use CSS visibility: hidden during refetch.
SolidJS peer dep is ^1.9.0 — .latest confirmed available.
Fix 3 — home.tsx overflow-hidden gap (S4 defensive)
Defensive — S4 is not routed in v2, but the component exists and the CSS bug is real.
Constraints & invariants
All edits are in the opencode fork, synced to the overlay via opencode:build + sync:apply.
Widget iframes are never remounted by the fix — context/theme updates stay on the postMessage bridge.
No fix targets a component that is not rendered in the reporter's layout (S4 fixes are explicitly marked defensive).
Open question
The exact surface has not been confirmed. The spec fixes the shared patterns across S1–S4 but cannot guarantee the reporter's surface is among them. @bc037: a screen recording would resolve this. If the surface is S3 (WorkbenchPanel) or the chat timeline virtualizer, a separate investigation is needed.
Testing
Test
Verifies
pnpm --filter amicode test
No regressions
Manual: open sessions flyout (S1), scroll down, wait 10s
Fix 1 — position held
Manual: open sessions flyout during live solve, scroll down
Fix 1 — position held across polling
Manual: open side-panel "home" tab (S2), trigger refetch
Fix 2 — no skeleton flash
Manual: narrow panel < 768px, scroll in home (S4)
Fix 3 — scroll works at all widths
Prior art
session.tsx:1674 — same class of bug (auto-scroll ResizeObserver snapping on any reflow), fixed by gating on session_working().
home-projects-view.tsx:349 — project list uses string-keyed <For> to avoid remounting.
sameProjectList() (home-projects.ts:126) — structural comparison already exists for project reconciliation.
intake: ready
spec: spec-20260911-153000-home-scroll-snap-back
review: approved-mechanical (manual, round 2 of 2; round 1 was blocking — wrong surface)
suggested_path: B
Important
Problem: Scrolling in the amicode dashboard snaps back to the top on every scroll-down attempt, making content below the fold unreachable. Reported on WSL2 (linux-x64).
Approach: Three targeted fixes addressing shared patterns across all scrollable surfaces — structural equality on
sessionListDirectoriesconsumers, visibility-based loading gates, and a defensive CSS overflow fix.Scope:
session-header.tsx,session-side-panel.tsx, andhome.tsxin the opencode fork overlay (fork-side edits, synced viaopencode:build+sync:apply). No schema, backend, or extension-host changes.Assumptions: The v2 layout is active (always ON for release builds). The reporter's "Development projects view" is one of the four candidate surfaces identified below — see Open question.
Original report
See first comment below for the full original bug filing by @bc037.
Context: harmoniqs.amicode v0.3.4 (linux-x64), WSL2, engine v1.18.29-amicode.26, "Development projects view in the extension UI."
Adversarial review
Reviewed manually (no
amicobinary). Round 1 was blocking: the original plan targetedHomeDesigninhome.tsx, which is not rendered in the v2 route tree — the "/" route goes toNewSessionLanding(app.tsx:781), which redirects to a session. Round 2 re-scoped to the actual rendered surfaces and passed (approved-mechanical). Spec on disk.Affected surface — ambiguous, four candidates
In the v2 layout, there is no standalone "home page" at "/". The reporter's "Development projects view" is one of these surfaces:
session-header.tsx:980overflow: hidden auto, max-height 70vhsession-side-panel.tsx:284overflow-y-autoon flex-1 divworkbench-panel.tsx:55overflow-y-autoon flex-1 divhome.tsx:1078overflow-y-autowithmd:overflow-hiddenparentRoot-cause analysis
Cause A —
sessionListDirectoriescreates fresh arrays that cascade refetchessessionListDirectories()(helpers.ts:69) always returns a new array. Every consumer that uses the result as a memo or query key triggers unnecessary downstream updates:session-header.tsx:730):activeSessionsmemo callssessionListDirectorieson every reactive tick → new session list →<For>re-renders all rows.home.tsx:293):projectDirectoriesmemo passes the fresh array as aqueryKeytosessionLoad→ refetch →isLoadingflashes true → session list unmounts → scroll resets.Evidence:
sameProjectList(home-projects.ts:126) already exists as a structural comparator for the project reconcile path.Cause B —
<Show>gates unmount content during async loading transitionsMultiple surfaces wrap scrollable content in
<Show when={!loading}>gates that unmount the list on any refetch:session-header.tsx:1070–1091): nested<Show>gates onfilteredActiveSessions().length > 0.home.tsx:1354):<Show when={!homeCardsLoading()}>unmounts the entire widget grid during resource refetch.session-side-panel.tsx:285–306):<Show when={widgetInfos().length > 0 && dashboard()}>.Cause C —
home.tsxresponsive overflow gap (S4 only)Parent has
md:overflow-hidden— below Tailwind 768px breakpoint, no clip. S4-only.Acceptance criteria
pnpm --filter amicode testpassesKey decisions
Fix 1 — Structural equality on
sessionListDirectoriesconsumershome.tsx:293(S4):const projectDirectories = createMemo(() => sessionListDirectories(projects(), focusedSync().data.project ?? []), + { equals: (a, b) => a.length === b.length && a.every((v, i) => v === b[i]) } )session-header.tsx:730(S1): extract directories into a structurally-compared memo so the session computation only re-runs when directories actually change:Then
activeSessionsreadsflyoutDirectories()instead of callingsessionListDirectoriesinline.Fix 2 — Prevent cards unmount on refetch (S2 and S4)
session-side-panel.tsx:285andhome.tsx:1354: replace binary<Show when={!loading}>with a visibility approach. Show skeleton only on initial load (!widgetsRaw.latest); use CSSvisibility: hiddenduring refetch.SolidJS peer dep is
^1.9.0—.latestconfirmed available.Fix 3 —
home.tsxoverflow-hidden gap (S4 defensive)Defensive — S4 is not routed in v2, but the component exists and the CSS bug is real.
Constraints & invariants
opencode:build+sync:apply.Open question
The exact surface has not been confirmed. The spec fixes the shared patterns across S1–S4 but cannot guarantee the reporter's surface is among them. @bc037: a screen recording would resolve this. If the surface is S3 (WorkbenchPanel) or the chat timeline virtualizer, a separate investigation is needed.
Testing
pnpm --filter amicode testPrior art
session.tsx:1674— same class of bug (auto-scroll ResizeObserver snapping on any reflow), fixed by gating onsession_working().home-projects-view.tsx:349— project list uses string-keyed<For>to avoid remounting.sameProjectList()(home-projects.ts:126) — structural comparison already exists for project reconciliation.intake: ready
spec: spec-20260911-153000-home-scroll-snap-back
review: approved-mechanical (manual, round 2 of 2; round 1 was blocking — wrong surface)
suggested_path: B