⚠️ Definition of Done: this issue must be completed in full, in a single PR. Do not split this
work across multiple PRs, and do not defer any Deliverable below to a follow-up issue. A PR that
satisfies only some of the Deliverables, stubs a required test, or leaves a checkbox
partially-done does NOT resolve this issue and will be closed.
Context
apps/loopover-ui/src/routes/app.analytics.tsx:172-175 calls
useLocalStorage<AnalyticsWindowDays>(ANALYTICS_WINDOW_STORAGE_KEY, DEFAULT_ANALYTICS_WINDOW_DAYS)
with no third legacyKey argument.
Two sibling routes correctly supply one: apps/loopover-ui/src/routes/app.runs.tsx:579-583
(useLocalStorage<SavedView[]>("loopover.runs.views", [], "gittensory.runs.views")) and
apps/loopover-ui/src/routes/app.workbench.tsx:33-37
(useLocalStorage<Tab>("loopover.workbench.tab", "miner", "gittensory.workbench.tab")).
apps/loopover-ui/src/lib/use-local-storage.ts's own doc comment explains why: "legacyKey, when
given, is read as a one-time fallback if key is absent (a rebrand key-rename migration)."
ANALYTICS_WINDOW_STORAGE_KEY was itself renamed from "gittensory.analytics.windowDays" to
"loopover.analytics.windowDays" in the same rebrand commit (75450f1d5) that added the
legacyKey migration pattern to other files — this file was simply missed.
grep -rn "gittensory.analytics" . returns zero hits anywhere else in the repo, confirming no
alternate migration path exists for this specific key.
Consequence: any user who had picked a 30-day or 90-day analytics window before the rebrand cutover
silently loses that preference and reverts to the 7-day default on their next visit, with no error
and no indication anything changed.
Requirements
- Add the legacy key
"gittensory.analytics.windowDays" as the third useLocalStorage argument in
app.analytics.tsx, matching the pattern already used by app.runs.tsx/app.workbench.tsx
exactly.
Deliverables
Both Deliverables are required in the same PR.
Test Coverage Requirements
apps/** is excluded from codecov/patch gating, but apps/loopover-ui's own local vitest
coverage thresholds apply — the new test must exercise the previously-missing migration path
directly.
Expected Outcome
A returning user's pre-rebrand analytics window preference is correctly migrated forward instead of
silently reverting to the default, matching the migration guarantee already provided for the runs
and workbench view preferences.
Links & Resources
apps/loopover-ui/src/routes/app.analytics.tsx:172-175 (the fix location)
apps/loopover-ui/src/routes/app.runs.tsx:579-583, app.workbench.tsx:33-37 (the already-correct
sibling pattern)
apps/loopover-ui/src/lib/use-local-storage.ts (legacyKey doc comment)
apps/loopover-ui/src/lib/use-local-storage.test.ts (existing migration-test pattern to mirror)
- Introduced/renamed by commit
75450f1d5
Context
apps/loopover-ui/src/routes/app.analytics.tsx:172-175callsuseLocalStorage<AnalyticsWindowDays>(ANALYTICS_WINDOW_STORAGE_KEY, DEFAULT_ANALYTICS_WINDOW_DAYS)with no third
legacyKeyargument.Two sibling routes correctly supply one:
apps/loopover-ui/src/routes/app.runs.tsx:579-583(
useLocalStorage<SavedView[]>("loopover.runs.views", [], "gittensory.runs.views")) andapps/loopover-ui/src/routes/app.workbench.tsx:33-37(
useLocalStorage<Tab>("loopover.workbench.tab", "miner", "gittensory.workbench.tab")).apps/loopover-ui/src/lib/use-local-storage.ts's own doc comment explains why: "legacyKey, whengiven, is read as a one-time fallback if
keyis absent (a rebrand key-rename migration)."ANALYTICS_WINDOW_STORAGE_KEYwas itself renamed from"gittensory.analytics.windowDays"to"loopover.analytics.windowDays"in the same rebrand commit (75450f1d5) that added thelegacyKeymigration pattern to other files — this file was simply missed.grep -rn "gittensory.analytics" .returns zero hits anywhere else in the repo, confirming noalternate migration path exists for this specific key.
Consequence: any user who had picked a 30-day or 90-day analytics window before the rebrand cutover
silently loses that preference and reverts to the 7-day default on their next visit, with no error
and no indication anything changed.
Requirements
"gittensory.analytics.windowDays"as the thirduseLocalStorageargument inapp.analytics.tsx, matching the pattern already used byapp.runs.tsx/app.workbench.tsxexactly.
Deliverables
app.analytics.tsx'suseLocalStoragecall for the analytics window preference includes the"gittensory.analytics.windowDays"legacy key.localStorage["gittensory.analytics.windowDays"] = "30", mountsProductAnalytics, and asserts the toggle group shows 30d selected andlocalStorage["loopover.analytics.windowDays"]is backfilled — mirroring the existingmigration tests already used for
app.runs.tsx/app.workbench.tsxinuse-local-storage.test.ts.Both Deliverables are required in the same PR.
Test Coverage Requirements
apps/**is excluded fromcodecov/patchgating, butapps/loopover-ui's own local vitestcoverage thresholds apply — the new test must exercise the previously-missing migration path
directly.
Expected Outcome
A returning user's pre-rebrand analytics window preference is correctly migrated forward instead of
silently reverting to the default, matching the migration guarantee already provided for the runs
and workbench view preferences.
Links & Resources
apps/loopover-ui/src/routes/app.analytics.tsx:172-175(the fix location)apps/loopover-ui/src/routes/app.runs.tsx:579-583,app.workbench.tsx:33-37(the already-correctsibling pattern)
apps/loopover-ui/src/lib/use-local-storage.ts(legacyKeydoc comment)apps/loopover-ui/src/lib/use-local-storage.test.ts(existing migration-test pattern to mirror)75450f1d5