Skip to content

Complete Dock 12.0.0.2 -> 12.1.0.2 upgrade: migrate legacy $id/$ref layouts that break the new reference handling #1348

Description

@JoshuaRowePhantom

Summary

The Dock.* pins are held at 12.0.0.2 because upgrading to 12.1.0.2 breaks deserialization of already-persisted ("legacy") dock layouts. Dock 12.1.0.2 (upstream PR danipen/Dock #1107 "Fix Owner reference-cycle handling across all serializers") widened the System.Text.Json $id/$ref reference-tracking scope so it no longer resets per-list. Legacy layouts written by 12.0.0.2 contain massively duplicated $id values (a per-list-isolated-scope artifact — the very bloat from #1335/#1334), which the 12.1.0.2 deserializer rejects. Impact: we cannot take the Dock upgrade (and its native #1107 reference-cycle fix that supersedes our #1335 workaround) until legacy persisted layouts are migrated. This is also a real user-facing MIGRATION risk: any user's already-persisted 12.0.0.2 layout would fail to load after the upgrade, not just the test fixture.

Root Cause

Affected Files

File Role
features\Directory.Packages.props (:17-21) Pins all five Dock.* at 12.0.0.2 (only CPM file under features\; no submodule variant) — to move to 12.1.0.2
features\Phantom.Workspaces\ViewModels\DockLayoutCanonicalizer.cs (:42-52,60-61,68-83,86-113) Preserve options, legacy-format detection, legacy DockSerializer deserialize path — migration pre-pass goes here
features\Phantom.Workspaces\ViewModels\WorkspaceDockTypeInfoResolver.cs (:128-157,144-157,195-208) Custom resolver ($type + $id/$ref ordering) — candidate for simplification once #1107 native handling is trusted
features\Phantom.Workspaces\ViewModels\MainWindowViewModel.cs (:2840 write, :3583/:3600 read) Persistence load/save call sites
features\Phantom.Workspaces.Tests\WorkspaceDockPersistenceTests.cs (:132-150) Failing test + Expected-Tests home
features\Phantom.Workspaces.Tests\Fixtures\dock-layout-1334.json Legacy bloated fixture with duplicate $ids

Design / Fix (ordered options)

  1. PRIMARY — legacy-layout migration pre-pass in DockLayoutCanonicalizer.Deserialize before the legacy DockSerializer.Deserialize call (:81): run a JSON-level transform that either (a) STRIPS all $id/$ref metadata from legacy-format JSON (only 3 $refs total — negligible sharing lost; Dock rebuilds from $type + inline objects), or (b) RENUMBERS $ids to be globally unique and rewrites the 3 $ref targets. Pure JSON transform, no Dock-internals dependency. Crucially this also unblocks any USER's already-persisted 12.0.0.2 layout on upgrade, not just the fixture.
  2. Regenerate the fixture under the current preserve write path (SerializeCanonical) as a secondary safety net so the test also covers the new persisted format; keep the legacy fixture behind a dedicated migration test.
  3. Bump the pins in Directory.Packages.props:17-21 to 12.1.0.2 for all five Dock.* together (never a partial subset — Bump Dock.Avalonia and Dock.Avalonia.Themes.Fluent #1339 only moved 2 of 5, which desyncs the set).
  4. Follow-up cleanup (after 1 lands): PR Crash: ObservableCollection reentrancy opening a tab — remove dock->Tabs order back-sync (Tabs order must be independent of dock) #1107 fixes the upstream per-list-isolation/Owner-cycle problem natively, so the heal/dedupe + ApplySerializationOrder machinery in WorkspaceDockTypeInfoResolver (and possibly CreatePreserveOptions) MAY be simplified toward Dock.Serializer.SystemTextJson's own serializer. Do NOT remove the heal/dedupe wholesale — it is still needed to reduce already-bloated persisted graphs (Dock-layout persistence leak: ActiveDockable/DefaultDockable/FocusedDockable and orphan floating Windows are inline-cloned every save (DockSerializer bypasses ReferenceHandler.Preserve), compounding to 100+ WorkspaceDocument instances for 11 tabs #1335). Note this simplification alone does NOT fix Review, validate, and merge all open Dependabot dependency-update PRs #1346 because the failing input is a pre-existing legacy file — option 1 is still required.
  5. When implementing, check whether Dock.Serializer.SystemTextJson 12.1.0.2 exposes a ctor/option to opt out of the new reference tracking (possible temporary escape hatch, not the long-term fix).

Verification: after migration + pin bump, WorkspaceDockPersistence_LoadRealLayout1334_HealsTo11Docs passes under 12.1.0.2; full dock persistence/tab-switch/layout suites green incl. stability run.

Expected Tests

Follow WorkspaceDockPersistenceTests convention Subject_Scenario_ExpectedOutcome (existing examples at :65,:93,:112,:135).

Test Name Class What It Verifies
WorkspaceDockPersistence_LoadLegacyLayoutWithDuplicateIds_MigratesAndHealsTo11Docs WorkspaceDockPersistenceTests The legacy dock-layout-1334.json (105× $id="1") deserializes under Dock 12.1.0.2 via the migration pre-pass and still heals to 11 docs
WorkspaceDockPersistence_Dock1210Upgrade_DeserializesLegacyFixtureWithoutIdConflict WorkspaceDockPersistenceTests Deserializing a legacy duplicate-$id layout does not throw the '$id' ... conflicts with an existing identifier error
DockLayoutCanonicalizer_LegacyJsonWithDuplicateIds_StripsOrRenumbersReferenceMetadata WorkspaceDockPersistenceTests (or a canonicalizer-focused test class) The migration pre-pass produces JSON with globally-unique (or absent) $ids and intact $ref targets

Related issues

Metadata

Metadata

Labels

bugSomething isn't workingdiagnosedRoot cause identifiedneeds-slow-testsRequires full test suite including slow Git tests at checkinnext-upverified-locallyImplementation has been verified locally

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions