Markdown tabs stuck loading — blob fetch uses display string as revision #172
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#172
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Markdown tabs stuck on "loading..." — blob fetch uses display SHA string as revision
On a Tree page with markdown files, the tabs render but content never loads (
loading…), and the tray shows:SHA:85AB5FBCC2BBCAB038377FD84741687BB6A19C64:BLOB:README not found: …85ab5fbcc….Root cause (from the error text — verify in code): the tab body fetch builds the blob request with the literal header-pill display string (
SHA:85AB5FBCC…, uppercased, with aSHA:prefix and what looks like aBLOB:READMEkey fragment) as the revision instead of the resolved ref/commit sha for the tree being viewed. The blob endpoint 404s because no such revision exists.Fix
{sha, path}through the existing blob endpoint/cache key; never interpolate UI display strings into API paths.Acceptance criteria
node --testgreen; browser check of a doc-heavy dir both themes, zero console errors + zero toasts; no new deps.Fixed by PR #173 (branch fix/issue-172). Root cause: DocTabs built its blob revision as t().sha ?? t().ref — the fallback interpolates a UI display string (full ref name) into the blob route's single-segment {rev}, splitting the route and 404ing every tab onto loading... forever. The SHA:... chip text is CSS-uppercased cache key (same misread class as #150), not the revision. Fix passes rev={t().sha} through the pure docFetchArgs gate (40-hex sha + encoded path, null = do not fetch); regression tests pin the fetch args. node suite 361/361 green; no browser drive per task constraints.
Review of PR #173 (fix/issue-172: tab fetch uses resolved revision) — verified in scratch worktree at origin/fix/issue-172 (
878cc72), worktree removed afterward. Main worktree left untouched (still clean on main).GATE (web/src/lib/doctabs.js:111-131): SHA_RE=/^[0-9a-f]{40}$/ admits ONLY 40-lowercase-hex — ref names with slashes, bare 'main', 12-char short shas, uppercase shas, 'SHA:'-prefixed chip text, empty/null/undefined all fall to null (rev is normalized via String(rev ?? '') before testing). Correct per case.
NULL-REV PATH (web/src/pages/Tree.jsx:99-112): selArgs() null → useData key 'doctabs:none', fetcher returns Promise.resolve(null) WITHOUT calling repoClient.blob → no request, and since no rejection reaches useData's start(), reportError (web/src/lib/data.js:121) never fires → no tray spam. Render falls to the existing 'loading…' fallback (Tree.jsx:146). Verified by reading, no browser (per instructions — node tests + reasoning only).
NO RECURRENCE OF '?? t().ref': grep over web/src/ finds zero '?? t().ref'/'?? t().sha'. Tree.jsx:215 now passes rev={t().sha}; the ONLY repoClient.blob call for tabs (Tree.jsx:111) sits behind the selArgs()/docFetchArgs guard, and the cache key (Tree.jsx:101) uses selArgs().rev too — the gate is the single choke point. docBlobPath's only remaining caller is docFetchArgs itself (doctabs.js:130).
CACHE KEY: unchanged when rev is valid — still
sha:<sha>:blob:<rawSelPath>, same shape the blob page builds in useResolved (data.js:339sha:${r.sha}:blob:...), so the shared-entry claim holds; no fork (key still uses raw selPath(), fetch uses the encoded args.path — #171 behavior preserved).LAZY-PER-TAB: preserved — per-sel useData, probed-readme pre-fill short-circuit (Tree.jsx:105-108) untouched, Infinity TTL untouched.
REGRESSION TESTS (doctabs.test.js:127-156): pin the contract (valid sha + encoded paths pass through; 9 display-string revs + empty names gate to null). They would fail pre-fix: docFetchArgs did not exist on main, so the import itself throws; and behaviorally the old
t().sha ?? t().ref+ direct blob(props.rev, ...) path fetched display strings verbatim.MISREAD CORRECTION: confirmed — no 'SHA:'-prefixed producer in web/src (grep finds only a sha.jsx comment and the test literal). App.jsx:90 renders the useData key verbatim in .chip and ui.css:55 gives .chip Tailwind uppercase, so the doc's display-vs-fetch explanation is accurate.
LAWS: 1 OK (4 files changed only — doc + Tree.jsx + doctabs.js + test; no manifest changes, stdlib-only code); 7 N/A (no async work added; null path resolves synchronously); 8 OK (web/ + doc only, no core imports); 12 OK (12_web_ui.md decision appended in the same change, claims verified accurate above).
TESTS: full suite 'node --test web/test/unit/*.test.js' → 361/361 pass (incl. 16/16 doctabs). Note: 3 data-layer test files initially failed in the scratch worktree with ERR_MODULE_NOT_FOUND solid-js because worktrees don't carry the ignored web/node_modules; re-ran via symlink to main's node_modules (read-only, removed with the worktree) → all green. 'vite build' in web/ → success (122 modules, built in ~2s).
No browser verification performed (per instructions). No changes pushed — none needed; nothing to fix.
MERGE RECOMMENDATION: ready to merge.
Fixed by PR #173 (review: gate + choke point + cache-key verified; 361/361 node tests), merged. Closing.