# Navigation performance This is the Phase 7 measurement and regression procedure for area switches. ## Local measurement 1. Start the existing local app and backend using the canonical PostgreSQL datastore. Do not create a performance-test database. 2. Use synthetic fixtures or an explicitly authorized dummy workspace. Open the development app at `http://127.0.0.1:5173/?measureNavigation=1` and load that workspace. Ordinary app URLs do not enable instrumentation; production builds exclude it. 3. Wait for the workspace to finish loading. Keep viewport, data, filter settings and development/production mode identical between comparisons. Stop concurrent builds and load tests before recording timings. 4. Click each main navigation area. Read `#assessor-navigation-performance` after the next three animation frames, waiting for `sequence` to advance. It exposes only `area`, `sequence`, `paintMs`, `longestFrameMs` and named calculation durations in `stepsMs`. The interval starts in the click capture handler. This measures click-to-render responsiveness, not the completion of backend requests. Check asynchronous readiness separately using control availability and row counts. Initial data loading must not overlap a navigation measurement. 5. Measure a first visit and at least two repeat visits. Test Work before and after opening Pathfinder, and test the return from Datahub and Result DB. Confirm that filter changes made while the graph is hidden are applied on reactivation and that a workspace change resets retained state. 6. Close temporary browser tabs after testing. Never copy customer content into timing reports. ## Known causes and controls | Cause found on 2026-09-09 | Control | | --- | --- | | Filter bar, sidebar and viewer independently repeated equivalent queries after remounts. | Shared bounded sheet selectors; reference/semantic keys include every input that changes the result. | | Status matching rescanned source fields for each consumer and facet. | Profile-owned weak record caches; keep the existing matching semantics and profile separation. | | Rejected numbered column groups reread all siblings for every column. | Reuse the group values, skip ineligible text columns early, stop eligibility checks beyond the category limit. | | Sort comparators normalized both records on every comparison. | Normalize once per record before sorting; preserve tie-breaking and null ordering. | | Work serialized every filtered finding into Raw Data text while displaying other modes. | Mount and memoize the complete text projection only in Raw Data. Derive titles only for rendered records. | | Virtualization initially mounted 40 rows before measuring the viewport. | Bound the first window by screen height plus overscan; use stable callback refs and reset cancelled frame handles. | | Work mounted 2,537 native sheet options on every visit to the authorized dummy. | Keep the selected option mounted; synchronously prepare all options before pointer opening or keyboard focus. Collapse on blur without changing selection. | | Export buttons scanned the workspace and constructed export rows during rendering. | Determine availability with a short-circuit check; construct the payload on the export action. | | Hidden Pathfinder built its graph, consumed context updates and measured hidden geometry. | First-activation mount, retained input boundary, scope reset, memoized component, paused hidden observers/animations. | | Graph text collision layout ran with text switched off; identical MITRE headers were repeatedly classified. | Gate text layout by display mode and reuse header classifications within each graph derivation. | | An unchanged periodic health response replaced the global app state. | Preserve state identity unless the health status changes. | | Repeated identical geometry observations replaced graph/dashboard state. | Compare dimensions and connector paths before setting state. | ## Regression checks `tests/features/navigation-performance.test.ts` exercises 8,257 synthetic records with repeated numbered columns. The unchanged repeat visit must read zero source fields. Smaller cases verify review, status, severity, search, path, profile, dataset and sheet invalidation, source preservation and bounded cache eviction. `tests/features/navigation-rendering.test.tsx` verifies retained-view suspension/resumption, raw-text reuse and the first virtual window. `tests/features/dataset-viewer-cost.test.tsx` mounts the actual viewer: Matrix must not read an offscreen finding's fields, while Raw Data must include its complete text. `tests/features/sheet-selection-cost.test.tsx` verifies 2,537 synthetic choices, pointer/keyboard preparation and preservation of the selected sheet after blur. Run the focused tests while iterating, then `npm test` and `npm run build`. Existing facet, severity, GPO, result-window and graph tests protect the underlying behavior. Timing output is diagnostic; CI uses deterministic behavior and operation counts rather than machine-dependent millisecond limits. ## Observations on 2026-09-09 Development browser, authorized dummy, 1280 × 720 viewport: the initial observed Work switch took 5,324 ms. After shared calculations, lazy raw text, bounded first rendering and deferred sheet options, unchanged Work revisits measured 121–211 ms, including two consecutive measurements of 136/138 ms. One return immediately after a filter reset and graph rebuild took 406 ms. These are individual observations, not a hardware-independent latency guarantee. The final cross-area sweep measured 34 ms for Result DB, 44 ms for DB Structure and 109 ms for Datahub until the third frame; their asynchronous data requests are not included. Client Info measured 353 ms on a warm visit, while the first visit after filter reset took 991 ms. Pathfinder still performs a necessary first build or rebuild after data/filter changes (1,005 ms after the reset in this sweep); retained unchanged visits avoid rebuilding its data. Continue measuring these separate cold costs when changing either area. The synthetic 8,257-record benchmark initially measured 5,360 ms cold / 398 ms repeated. Focused post-change runs measured 623–978 ms cold / 1 ms repeated; concurrent full-suite load raised cold times, so those runs are not directly comparable. The reliable regression invariant is zero source-field reads on an unchanged repeat visit. No tenant data, source artifacts or database schema were changed for these measurements.