Skip to content

createState decodes a corrupt editorPct/sideSplitPct/cellDrawerPx/docPanePx to NaN #570

Description

@BorisTyshkevich

Spotted while shipping #487 phase 1 (src/core/left-nav-layout.ts), deferred as out of scope.

The problem

clamp (src/core/format.ts:8) is not NaN-safe — Math.max(lo, Math.min(hi, NaN)) is NaN.
Four createState decoders in src/state.ts feed a parsed localStorage string straight into
it, so a corrupt, truncated or hand-edited value decodes to NaN rather than to the
documented default:

Field Key Site
editorPct asb:editorPct src/state.ts — via the local num() helper
sideSplitPct asb:sideSplitPct src/state.ts — via num()
cellDrawerPx asb:cellDrawerPx src/state.tsclamp(parseInt(...), 320, Infinity)
docPanePx asb:docPanePx src/state.tsclamp(parseInt(...), 320, Infinity)

A NaN geometry value reaches the DOM as width: NaNpx / height: NaN%, which the browser
drops — so the pane collapses or takes an unstyled default with nothing in the UI to explain
it, and the bad value stays persisted across reloads.

sidebarPx had the same hole and was fixed in #487 phase 1 (clampWideWidthPx) because that
key is the left navigation's wide width, which the phase owns. The other four were left
alone deliberately — they belong to the editor/results splitter, the sidebar's vertical split,
the cell-detail drawer and the docs pane, none of which #487 touches.

Suggested fix

Either make clamp itself NaN-safe (it has many callers — needs an audit of whether any
depend on NaN propagating), or give these four decoders an explicit finite-check-and-default
the way clampWideWidthPx / clampDrawerWidthPx do. The latter is the smaller change and
keeps each key's documented default next to the key.

Each fix needs a createState test case with a non-numeric stored value, alongside the
existing "reads + clamps persisted prefs" case in tests/unit/state.test.ts.

Metadata

Metadata

Assignees

No one assigned

    Labels

    inboxFiled mid-task; not yet triaged into the roadmap

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions