Layer identity and compatibility boundaries
MVR Layer UUIDs own persistent identity. Layer::name is authored presentation
metadata; empty and equal names are valid in the repository's official MVR 1.6
schema. Imported layers are never coalesced or renamed to satisfy a GUI label
policy. Canonical UUID spelling may normalize representation without replacing
the effective UUID. The specification/XSD basis remains the pinned provenance
in Architecture.
Fixture, Truss, Support, SceneObject, and GroupObject own layerUuid.
Export, grouping, deletion, Query membership, visibility, and current-layer
selection use UUIDs. Rename changes metadata and refreshes derived labels; it
never changes object ownership. An authored foreign layer called No Layer is
not special. Only the canonical application default UUID identifies the default
layer, and only that identity is protected from user rename/deletion.
Core's GUI-independent layer_identity API owns UUID lookup, presentation
labels, compatibility resolution, default creation, and migration. Empty names
are presented as [<UUID>]; equal names get a full UUID suffix. These labels
never overwrite Layer::name or enter standard MVR fields. User-created names
still follow the separate LayerService UI policy: nonempty, bounded, and unique.
Imported names are not subject to that policy.
Default and legacy migration
The application default is a normal Layer named No Layer, with UUID
DeriveDeterministicUuid("mvr:layer:default"). Fresh project setup and production
creation allocate canonical identities immediately. layer_default is accepted
only as legacy input and maps deterministically to this default UUID. No
production creation path emits that token or a layer_<timestamp> identity.
The shared MVR reader retains every Layer, even empty layers with empty names.
It preserves valid UUIDs, repairs malformed/missing/conflicting source identities
once in the parsed editable scene, and assigns children by the parsed Layer UUID.
Source metadata used by Inspector remains separately recorded as authored.
The legacy layer_default spelling uses the same canonical default policy.
MigrateLayerMembership is an explicit import/mutation compatibility boundary.
For missing ownership, it prefers explicit child ownership, then unambiguous
legacy label/name resolution. Absent legacy layers are inferred deterministically
from their names. Ambiguous legacy assignments without child ownership are kept
in a distinct inferred layer; migration does not guess between existing UUIDs.
Repeated migration is idempotent. A nonempty authoritative ownership reference
is never replaced by a name merely because the label disagrees.
Project and workspace state
.pstg persists scene identity through canonical scene.mvr, so the standard
Layer/ChildList graph carries UUID ownership without a private MVR extension.
Project restore uses the same reader and migration. view_hidden_layers now
stores UUIDs; older name entries are resolved on load. A historical hidden name
shared by several layers hides those same layers after migration. Current-layer
selection is saved as view_current_layer_uuid; old projects lacking that key
select the canonical application default. History snapshots include UUID state
and object ownership, preserving Undo/Redo across rename and delete.
Remaining compatibility text
The old object layer string remains a derived label, because existing table
widgets, natural sorting, and parts of GUI cache invalidation consume display
text. Table adapters prepare label edits without mutating the scene, then commit
UUID ownership after the Undo snapshot; creation adapters call AssignLayer. All persistent
ownership decisions use layerUuid. Replacement/conversion paths copy UUID
ownership independently. GetLayerNames remains a presentation API returning
unique labels; UUID enumeration is separate and does not collapse names.
Low-level LayerVisibilityState still accepts string tokens for old callers;
ConfigManager resolves project/workspace inputs through the domain API before
publication, and render/picking paths consume UUIDs. Legacy MVR appearance maps
may resolve colors by name only when UUID-keyed appearance is unavailable; that
fallback never chooses membership or changes identity.
Follow-up: replace the remaining table display strings with explicit UUID/value choices and compute labels at presentation time. This would remove the derived object label cache without changing the domain or standard serialization.
Defensive export boundary
RecoverSceneIdentities remains enabled. Export preparation and canonical
snapshots operate on a private copy; read-only snapshots do not migrate or dirty
the live scene. Import and legacy load store migration results in editable state,
so normal export does not repeatedly repair application-generated identities.
Malformed, missing, duplicate, conflicting, or unresolved identities introduced
later still produce the established diagnostics. Representation normalization
and source identity preservation remain separate concerns.