VisSelect renders nothing (opaque render path) — profile visibility selector needs a working live-render rig #410
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#410
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?
What's requested
The profile visibility selector (VisSelect) renders nothing — the component goes through an opaque render path and the page shows an empty selector. Diagnose why the render path is opaque, fix it, and give the visibility selector a working live-render rig so the render path can be observed while changing profile visibility.
Research-first
Diagnose before fixing — the render path must be understood and documented (why the component doesn't reach the DOM, why props children isn't invoked, why props children fn signature
(item, i)mismatches the adapter's children fn returningo.label) before the fix is written. The fix shape and acceptance criteria below are hypotheses to validate against the research.Hypotheses to validate (fix shape as hypothesis)
(item, i)— document the actual invocation shape from the research.props.childrenis called before the mapArray each/array accessor is populated — validate whetherprops.childrenis undefined at invocation time (the observedCannot read properties of undefined (reading 'value')+ 404 on the runtime file).Acceptance criteria (checkboxes)
Additional finding from the interrupted investigation (preserved from its scope probe, verified passing locally):
visibilityOptions()returns fresh (non-identical) arrays and objects on every call (web/src/lib/visibility.js). Verified with a node test: two calls producedeepEqualarrays but different object identity. Consequence in the Settings select: Solid's<For>treats each invocation as new items (reference identity) and rebuilds every<option>node wheneverisOrg()flips — and since the value signal does not change, the select never re-renders its selected value and the DOM falls back to the first option (public). This is the render-side mechanism behind the stale display, on top of the 5s-TTL prefill gate documented in the ticket body.The probe file (
web/test/unit/visibility-options-for-test.js) was left untracked in the working tree; its assertion belongs in the fix's test set (an identity-stable options array — hoisted constant or memo — plus the prefill/refresh pinning already in the acceptance criteria).Fix ready for review: PR #412 (#412, branch fix/issue-410).
Research verdicts (evidence in the PR + docs/features/01_identity_permissions.md Decisions): H1 CONFIRMED (mapper shape is (item, index-accessor), never (item, raw-number) or o.label-as-item), H2 CONFIRMED as adapter bug (real mapArray never yields undefined items with a populated each), H3 REFUTED for production (runtime ships inside the vite bundle; the 404 was a bypass-the-build harness artifact). The #4065 identity finding held and is fixed with hoisted frozen option constants.
Acceptance: VisSelect renders the populated selector through the real path (Settings + Access share it); live-render observed headless through the genuine solid-js For in web/test/unit/vis-select.test.js (9/9; full suite 816/818 with only the 2 pre-existing environmental smoke fails); no adapter/runtime hacks. One item stays open: a real-Chromium drive (loopback-blocked in this environment) — requested on review hardware.
Review of PR #412 (fix/issue-410) — verified in scratch worktree, all checks done there; main worktree untouched.
RESEARCH CLAIMS — all hold against solid-js@1.9.15 installed source:
SHARED VisSelect (web/src/components/VisSelect.jsx:29-40): real For path, arity-1 (o) mapper, each=visibilityOptions(props.isOrg), value={props.value ?? ''} preserves the #394 blank-while-unseeded rule ('' matches no option). user→org relabel correct (private — owner only vs — org members only, via visibility.js frozen constants). No adapter, no jsx-runtime import.
SETTINGS + ACCESS ADOPTION: behavior preserved. Settings.jsx keeps the full #394 machinery (visibilityReseed reseed/rebase/isDirty, saveVisibilityOnly, visDirty gating — lines 40-41, 92-193 untouched); only the inline select became <VisSelect value/disabled/onChange/isOrg>. Access.jsx same; gains default aria-label='Visibility' (additive; its inline select had none). For imports in both files stay used by other lists — no unused imports. One non-regression note: isOrg is captured once (isOrg() passed as a plain prop, same as the old inline each={visibilityOptions(isOrg())}), so owner-kind flips after mount don't re-fire options in either version — identical behavior, not a regression.
LIVE-RENDER RIG (vis-select.test.js, 9 tests, all pass): genuine For from solid-js/web + createComponent, no stubs — real contract. Observes selected-mark following public→private→authenticated and surviving the user→org flip with relabel (no fallback to public). H1/H2 pins assert defined object items + function-type index arg. Would catch an adapter regression via the static guards (no mapArray(/jsx-runtime, exact <For each=> + {(o) =>} strings). Caveat (by design, documented): under plain node the SSR build executes, and the .jsx itself can't run without the vite transform — the rig drives the headless visRows model + real For with the identical mapper shape, which is the closest node allows; honest per law 11 (DOM thin).
LAWS: (1) no new deps — package.json untouched, diff is docs+web only, 7 files; (7) N/A, no long work; (8) no seam violation — shared component + lib module, no new capability, core pkgs untouched; (12) research written to 01_identity_permissions.md Decisions (#410 entry) in the same change. No backend change (name-only diff: 1 doc + 6 web files).
TESTS: full node suite in scratch worktree: 815 pass / 0 fail / 3 skipped (smoke tests skip with no server; note: a foreign auth-gated server answers on 127.0.0.1:8080 here, so smoke tests fail against it with 401 — environmental, unrelated to this PR). vis-select.test.js 9/9 pass after my fix. vite build: clean (593KB bundle warning only, pre-existing shape).
FIX APPLIED: comment typo in VisSelect.jsx:16 ('The Word "jsx runtime"' → 'The "jsx runtime"'), committed
dab5749and pushed to origin/fix/issue-410, re-tested 9/9 green.No browser drive per task scope (node tests + reasoning; JSX transform verified via vite build instead).
MERGE RECOMMENDATION: ready to merge.
Fixed by PR #412 (review clean — research verified against solid source, ===-diff finding real, rig genuine, #394 rule kept), merged. Closing.