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
Each write has its own gate (_suppressHashWrite, freshness checks, etc.). When something goes wrong with URL state, the answer to "which writer wrote that?" is non-obvious.
Then boot, hashchange, user camera movement, and share/copy call clear, intention-revealing paths.
Also flagged: moveEnd currently only writes the URL — sub-percentageChanged moves still bypass the rest of the camera-settled pipeline (sample reloads, cluster count refresh). If a small pan is important enough to update the URL, it should probably update the in-view stats too. A unified "settled-camera reconciliation" path would solve both.
Smell 2: Dual mode state
explorer.qmd carries the current mode in two places:
Closure-private mode variable (used by the camera-changed handler at lines 1971+)
Public viewer._globeState.mode (used by buildHash, tests, harnesses)
They're updated together today but the duplication is fragile. The Playwright investigation harness's iter 1 captured viewer._globeState.mode === 'cluster' shortly after waitReadyAndPointMode saw mode === 'point' — empirical evidence of transient sync mismatch.
Fix shape: make _globeState.mode the single source of truth, and wrap mode transitions in one setter (setExplorerMode(next, opts)). Add an invariant assertion / dev-time console log when the two diverge until the closure variable can be deleted.
Sequencing
Probably:
Collapse mode to single source (smell 2) — smaller, sets the foundation.
Introduce writeGlobeHash + setExplorerMode and migrate the writers (smell 1).
Route both camera.changed and camera.moveEnd through a single reconcileCameraState(reason) that does URL write + viewport stats + sample reload as appropriate.
Each step is a separate PR. Codex review at each step is recommended given the structural nature.
Acceptance
Single source of truth for mode.
Single explicit URL-write API; old direct history.{push,replace}State call sites migrated.
camera.moveEnd and camera.changed share the same settled-camera reconciliation entry point.
Structural follow-up from Codex's retrospective on #203 + #205. Two related smells; addressing them together because they touch the same code paths.
Smell 1: Many URL writers, no single boundary
Across
explorer.qmdthere are now (at least):pushStateenterPointMode/exitPointModewriteQueryState()— query-string filterscamera.moveEndlistener (explorer: add camera.moveEnd URL-write backstop (closes #204) #205)replaceStateEach write has its own gate (
_suppressHashWrite, freshness checks, etc.). When something goes wrong with URL state, the answer to "which writer wrote that?" is non-obvious.Codex's sketched interface:
Then boot, hashchange, user camera movement, and share/copy call clear, intention-revealing paths.
Also flagged:
moveEndcurrently only writes the URL — sub-percentageChangedmoves still bypass the rest of the camera-settled pipeline (sample reloads, cluster count refresh). If a small pan is important enough to update the URL, it should probably update the in-view stats too. A unified "settled-camera reconciliation" path would solve both.Smell 2: Dual
modestateexplorer.qmdcarries the current mode in two places:modevariable (used by the camera-changed handler at lines 1971+)viewer._globeState.mode(used bybuildHash, tests, harnesses)They're updated together today but the duplication is fragile. The Playwright investigation harness's iter 1 captured
viewer._globeState.mode === 'cluster'shortly afterwaitReadyAndPointModesawmode === 'point'— empirical evidence of transient sync mismatch.Fix shape: make
_globeState.modethe single source of truth, and wrap mode transitions in one setter (setExplorerMode(next, opts)). Add an invariant assertion / dev-time console log when the two diverge until the closure variable can be deleted.Sequencing
Probably:
modeto single source (smell 2) — smaller, sets the foundation.writeGlobeHash+setExplorerModeand migrate the writers (smell 1).camera.changedandcamera.moveEndthrough a singlereconcileCameraState(reason)that does URL write + viewport stats + sample reload as appropriate.Each step is a separate PR. Codex review at each step is recommended given the structural nature.
Acceptance
mode.history.{push,replace}Statecall sites migrated.camera.moveEndandcamera.changedshare the same settled-camera reconciliation entry point.Refs