diff --git a/src/lib/__tests__/insights-layout.test.ts b/src/lib/__tests__/insights-layout.test.ts index c68033ce7..b637a385f 100644 --- a/src/lib/__tests__/insights-layout.test.ts +++ b/src/lib/__tests__/insights-layout.test.ts @@ -76,6 +76,14 @@ describe("resolveInsightsLayout — v1 → v2 forward upgrade", () => { visible: false, order: 1, }); + + // v1.22 — a late-added default tile the saved blob never enumerated + // (e.g. `steps`, which entered the set in v1.12) merges in + // default-VISIBLE, matching the fresh-account default. The old + // force-hidden merge silently dropped its nav pill on every read of an + // existing or iOS-synced layout. + const steps = resolved.tiles.find((t) => t.id === "steps"); + expect(steps?.visible).toBe(true); }); it("returns the full default layout for garbage input", () => { diff --git a/src/lib/insights-layout.ts b/src/lib/insights-layout.ts index 44cba5e6f..7b2d3367a 100644 --- a/src/lib/insights-layout.ts +++ b/src/lib/insights-layout.ts @@ -215,7 +215,14 @@ export function resolveInsightsLayout(raw: unknown): InsightsLayout { }); // Merge with defaults so new tiles introduced in later versions show - // up automatically (invisible by default, the user opts in). + // up automatically. v1.22 — appended tiles inherit the default's + // visibility (`visible: true` for every default tile) instead of being + // force-hidden. The old default-invisible override silently dropped the + // pill for any late-added tile id (e.g. `steps`, which entered the set in + // v1.12) on every read of an existing or iOS-synced layout that didn't + // enumerate it, so it never matched the fresh-account default. The + // per-tile data floor (`summaries[...].count > 0` at the call site) still + // keeps an empty metric from bloating the nav. const savedIds = new Set(filtered.map((t) => t.id)); const missing = DEFAULT_INSIGHTS_LAYOUT.tiles.filter( (t) => !savedIds.has(t.id), @@ -223,7 +230,6 @@ export function resolveInsightsLayout(raw: unknown): InsightsLayout { const maxOrder = Math.max(0, ...filtered.map((t) => t.order)); const appended = missing.map((t, i) => ({ ...t, - visible: false, // default-invisible on auto-upgrade order: maxOrder + 1 + i, }));