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
Part of #280 (Dashboard as a first-class module). Phase 2 of 6, after Phase 1 (contracts). Normative spec in #280.
Goal
Browser persistence moves from flat per-feature localStorage keys to one atomic StoredWorkspaceV1 aggregate behind WorkspaceRepository, with one-shot migration from legacy keys.
Scope (from #280 "Phase 2: atomic persistence and migration")
WorkspaceRepository with atomic replacement semantics: validate the complete candidate before writing; publish committed state only after persistence succeeds; failed persistence leaves the previous stored workspace intact, the draft dirty, and revision unchanged; never partially replace queries/dashboard/layout/metadata.
Legacy migration exactly per Make Dashboard a first-class module with one-dashboard-per-current-workspace v1 UX #280 "Legacy migration marker": runs only when no aggregate exists; builds the initial Dashboard from legacy favorites; converts legacy layout preferences (asb:dashLayout, asb:dashCols, …) to flow@1; validates the whole candidate; persists atomically; legacy keys untouched until the aggregate write succeeds.
Multi-tab policy: last successful commit wins; documented; test proving a commit never produces a partially mixed workspace.
Decisions to settle in this phase
Storage mechanism for the aggregate.Make Dashboard a first-class module with one-dashboard-per-current-workspace v1 UX #280 doesn't name it. Single localStorage key collides with the ~5 MB origin quota vs maxDecodedJsonBytes = 10 MiB; IndexedDB (already required for Phase 6 token handoff) gives real atomicity and headroom. Decide here, and reconcile Phase-1 limits.
spec.favorite dual-write removal path.Make Dashboard a first-class module with one-dashboard-per-current-workspace v1 UX #280 allows a temporary dual-write during migration "with a documented removal path" — define that path concretely here (what flips membership reads to dashboard.tiles, which release deletes the dual-write) so it cannot become permanent.
Dependencies
Phase 1 (schemas/validation/canonical encoder). Coordinate with #276 phase 4 (AppPreferences service) so preference persistence isn't extracted twice.
Tests
Per #280 "Workspace persistence and migration": atomic commit; failed write preserves prior workspace + dirty draft + revision; migration runs once keyed on aggregate existence; legacy keys survive until successful commit; multi-tab last-write-wins never mixes aggregates.
Acceptance
Reload loads StoredWorkspaceV1; Dashboard state is no longer recomputed from favorites.
Migration is one-shot, atomic, and lossless for existing users.
Part of #280 (Dashboard as a first-class module). Phase 2 of 6, after Phase 1 (contracts). Normative spec in #280.
Goal
Browser persistence moves from flat per-feature localStorage keys to one atomic
StoredWorkspaceV1aggregate behindWorkspaceRepository, with one-shot migration from legacy keys.Scope (from #280 "Phase 2: atomic persistence and migration")
WorkspaceRepositorywith atomic replacement semantics: validate the complete candidate before writing; publish committed state only after persistence succeeds; failed persistence leaves the previous stored workspace intact, the draft dirty, and revision unchanged; never partially replace queries/dashboard/layout/metadata.asb:dashLayout,asb:dashCols, …) toflow@1; validates the whole candidate; persists atomically; legacy keys untouched until the aggregate write succeeds.Decisions to settle in this phase
maxDecodedJsonBytes = 10 MiB; IndexedDB (already required for Phase 6 token handoff) gives real atomicity and headroom. Decide here, and reconcile Phase-1 limits.spec.favoritedual-write removal path. Make Dashboard a first-class module with one-dashboard-per-current-workspace v1 UX #280 allows a temporary dual-write during migration "with a documented removal path" — define that path concretely here (what flips membership reads todashboard.tiles, which release deletes the dual-write) so it cannot become permanent.Dependencies
Phase 1 (schemas/validation/canonical encoder). Coordinate with #276 phase 4 (
AppPreferencesservice) so preference persistence isn't extracted twice.Tests
Per #280 "Workspace persistence and migration": atomic commit; failed write preserves prior workspace + dirty draft + revision; migration runs once keyed on aggregate existence; legacy keys survive until successful commit; multi-tab last-write-wins never mixes aggregates.
Acceptance
StoredWorkspaceV1; Dashboard state is no longer recomputed from favorites.