gabriel / musehub public
Closed #168 Bug
filed by gabriel human · 22 days ago

bug: page unscrollable after navigating from issue to file/blob view — requires hard refresh

0 Anchors
Blast radius
Churn 30d
0 Proposals

Summary

Navigating from an issue page to a file/blob view (e.g. issue #167 → its linked .md blob view) leaves the page unable to scroll — both mouse wheel and spacebar are dead — until a hard refresh (Ctrl+R).

Repro steps

  1. Open issue #167
  2. Click the "Full detail" link, which navigates to the blob view
  3. Attempt to scroll below the fold — mouse wheel and spacebar both do nothing.
  4. Hard refresh (Ctrl+R) — scrolling works normally again.

Console errors observed (filtered)

Two real, separate signals showed up in the console on both pages (the third block of contentscript.js / SES "Removing unpermitted intrinsics" warnings is a browser-extension artifact — SES lockdown from a wallet extension like MetaMask — unrelated to MuseHub, excluded here):

1. Real CSP misconfiguration — confirmed in code:

Executing inline script violates the following Content Security Policy directive
'script-src 'self' https://static.cloudflareinsights.com'. Either the 'unsafe-inline'
keyword, a hash (...), or a nonce ('nonce-...') is required to enable inline execution.
The action has been blocked.

Root cause found in musehub/main.py (~line 108-120): the CSP script-src directive allows 'self' and https://static.cloudflareinsights.com but has no 'unsafe-inline', nonce, or hash allowance. musehub/templates/musehub/base.html line 4 has an inline <script> (dark/light theme detection from localStorage) that this CSP blocks on every single page load. A second inline script (likely injected by the Cloudflare Insights beacon itself once/if it loads) is blocked the same way. This reproduces on both pages in the report, at the line number of each page's own inline script tag.

2. ERR_BLOCKED_BY_CLIENT on static.cloudflareinsights.com/beacon.min.js — most likely an ad-blocker/privacy extension blocking the Cloudflare Insights domain client-side, not a MuseHub bug.

The scroll bug specifically

Not yet root-caused with certainty. musehub/templates/musehub/static/app.js has several htmx:afterSwap listeners and keydown handlers; a plausible mechanism is that a JS error thrown elsewhere on the page (possibly the CSP violation above throwing before some initialization completes) leaves a scroll-related listener or state half-initialized until a full reload resets it. This needs a focused repro in a clean browser profile (no extensions) to isolate whether the CSP violation is actually the trigger, or whether it's an unrelated htmx/keydown handler bug.

Suggested next steps

  1. Add a nonce or nonce-based CSP to allow the two legitimate inline scripts (theme detection, Cloudflare beacon's injected snippet) — closes the CSP violation cleanly.
  2. Reproduce the scroll bug in a clean browser profile (no extensions) to rule out extension interference, then bisect app.js's keydown/htmx:afterSwap handlers to find what's left in a bad state after navigation.
Activity1
gabriel opened this issue 22 days ago
gabriel 22 days ago

Root cause found and fixed.

HTMX boost (hx-boost="true" on .container-wide in base.html) swaps <body>'s content but never touches <body>'s own class attribute. Issue pages use body_class="app-shell" (a bounded-height flex layout where <body> and #content have overflow: hidden and an inner column owns the actual scroll). The blob/file view does not use app-shell. Navigating between them via a boosted link left the stale app-shell class — and its overflow: hidden — stuck on <body>, with no inner scroll container on the new page to compensate. Nothing could scroll until a hard refresh re-rendered <body> from scratch.

Fix: expose the resolved body_class as data-body-class on #content (which does get freshly rendered on every boosted swap), and re-sync document.body.className from it on every htmx:afterSettle (syncBodyClassFromContent() in src/ts/musehub.ts).

Verified:

  • Unit test covering the sync function (src/ts/musehub.test.ts)
  • Playwright repro against local dev, confirmed as a clean A/B (reverting the fix reproduces the bug exactly: stale app-shell class, overflow: hidden, no scroll)
  • Playwright repro against the exact original scenario on live staging — issue #167 → its linked blob page — confirms body class resets, overflow becomes visible, and the page scrolls

Merged to dev, deployed to staging.

closed this issue 22 days ago