From 9a7f67b6349322576be058de2ae9c66434d97ee1 Mon Sep 17 00:00:00 2001 From: Paul Trowbridge Date: Wed, 16 Sep 2026 22:34:27 -0400 Subject: [PATCH] Keep the depth tracing, but silent unless localStorage.pf_debug is set The refocus timing is the sort of thing that will shift again -- a Perspective upgrade, a different machine, a slower load -- and rebuilding this instrumentation from scratch each time is wasted work. So it stays, behind a flag, instead of being reverted. probeView() returns before touching the viewer when the flag is off, since it calls getView() purely to report identity. Note for whoever reads the log next: the view ids it prints cannot be used to detect a rebuild. getView() hands back a fresh wrapper object on every call, so consecutive calls always look "rebuilt". The reliable signal is whether the re-apply throws "No table set". Co-Authored-By: Claude Opus 5 (1M context) --- ui/src/views/Forecast.jsx | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/ui/src/views/Forecast.jsx b/ui/src/views/Forecast.jsx index 8afcbae..d3e298f 100644 --- a/ui/src/views/Forecast.jsx +++ b/ui/src/views/Forecast.jsx @@ -203,15 +203,21 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio // fresh view has no depth set, so the whole tree appears expanded. Re-apply the // depth we last set once the redraw has settled. // ---------------------------------------------------------------- DEBUG - // Temporary instrumentation for the "row groups re-expand on refocus" bug. - // set_depth() and per-node expand/collapse live on the *view*, not in - // ViewConfig, so a rebuilt view loses both. These lines exist to show whether - // that is what happens. Remove once the cause is known. + // Tracing for the "row groups re-expand on refocus" bug. set_depth() and + // per-node expand/collapse live on the *view*, not in ViewConfig, so every + // view rebuild starts fully expanded and we have to re-apply depth ourselves. + // Silent unless localStorage.pf_debug is set, since this is the kind of thing + // you want back the next time the timing shifts. + // + // localStorage.setItem('pf_debug', '1') // then reload const viewSeqRef = useRef(0) const viewIdsRef = useRef(new WeakMap()) const lastViewIdRef = useRef(null) function dbg(msg, extra) { + let on = false + try { on = !!localStorage.getItem('pf_debug') } catch { /* private mode */ } + if (!on) return const t = new Date().toISOString().slice(11, 23) if (extra !== undefined) console.log(`[pf-depth ${t}] ${msg}`, extra) else console.log(`[pf-depth ${t}] ${msg}`) @@ -226,6 +232,9 @@ export default function Forecast({ sources = [], sourceId, versions = [], versio // Read the viewer's current view and report whether it is the same object we // saw last time. A changed id means the view was discarded and rebuilt. async function probeView(where) { + let on = false + try { on = !!localStorage.getItem('pf_debug') } catch { /* private mode */ } + if (!on) return const viewer = viewerRef.current if (!viewer) return dbg(`probe(${where}): no viewer`) try {