MVR exporter diagnostic behavior

MVR export reports MvrExportDiagnostic records rather than treating log text as presentation data. Each record has a stable code, Info/Warning/Error severity, semantic impact, explicit user-visibility policy, optional object and resource context, and a technical detail for logging. The model is independent of wxWidgets.

Classification policy

The exporter classifies the effect of recovery, not just its original reason. Canonical UUID spelling changes, inferred layers, safely recovered duplicate identity fields, transform recalculation that preserves world transforms, legacy Position remapping, normal pruning, successful GDTF canonicalization, and requested Symbol/Symdef preservation or flattening are Info and log-only. In particular, uppercase, braced, or otherwise noncanonical spelling represents the same UUID and is not a user warning.

Meaningful identity replacement, cleared references, duplicate numeric fixture IDs, fallback or missing GDTFs, omitted resources or textures, placeholder or empty geometry, rejected foreign metadata, omitted invalid DMX addresses, and an unavailable requested compatibility representation are user-visible Warning records. Structural validation, transform integrity, canonicalization, archive I/O, and hierarchy recursion failures are user-visible Error records and make the operation fail.

Identity storage mismatches are evaluated using both sources. A malformed or missing field remains log-only when the other source preserves the effective identity; two different valid identities produce one IdentityConflict, while two unusable sources produce one IdentityGenerated. Unresolved non-empty Position references produce ReferenceCleared because the reference is omitted. Failure to create a required physical-property GDTF patch or mandatory SceneObject placeholder geometry is fatal rather than silently exporting stale properties or deleting the object.

The stable code policy is:

Codes Severity Normal UI
IdentityCanonicalized, LayerInferred, TransformRepaired, InternalRecovery Info Hidden
IdentityGenerated, IdentityReassigned, IdentityConflict, ReferenceCleared, SymbolIdentityReplaced, FixtureIdReassigned Warning Shown
GdtfFallbackUsed, GdtfMissing, TrussGdtfMissing, GdtfPatchFailed Warning Shown
TextureMissing, ResourceMissing, ResourceDuplicate, SupportGeometryMissing, PlaceholderGeometryUsed Warning Shown
CompatibilityRepresentationUnavailable, ForeignMetadataDiscarded, DmxAddressOmitted Warning Shown
TransformInvalid, StructuralValidationFailed, CanonicalizationFailed, ArchiveIoFailed, HierarchyRecursion Error Shown; export fails

GetExportDiagnostics() is the authoritative API. GetExportWarnings() is a temporary compatibility view built from non-Info structured records; callers must not infer policy by parsing its English text.

Non-fatal warnings

When GeneralSceneDescription.xml references a fileName/GDTFSpec entry that is missing from the archive source set, or the same archive path appears more than once, export continues and records a warning:

  • Missing file warning: Referenced file '<name>' is missing from the archive and will be omitted.
  • Duplicate file warning: Referenced file '<name>' appears multiple times; duplicates will be ignored.

Diagnostics are available through MvrExporter::GetExportDiagnostics() after ExportToFile(...)/ExportToBuffer(...).

Live resource dependency pruning

Resource pruning follows the complete live dependency graph. File-bearing XML elements such as Geometry3D and GDTFSpec are direct MVR references. A live 3DS, glTF, or GLB model may in turn reference root-level external resources, including bitmap images and glTF binary buffers; those model-internal files are transitive dependencies and remain in the archive even though the scene XML does not name them directly. Resources outside both sets are stale and are pruned, so deleting a model also removes dependencies used only by that model.

Dependency discovery uses the resolved model source selected for export, including a model recovered from packaged scene resources. External dependency filenames remain identical to the model URI or bitmap filename. A case-insensitive archive-name collision between different source files fails export rather than silently renaming one side and breaking the model reference. Embedded data: URIs and remote HTTP(S) URIs do not require or trigger archive resource collection.

Fatal errors

Structural MVR compliance errors still fail export (for example missing GeneralSceneDescription, invalid version, or invalid required IDs). Every export-abort path retains a structured Error for the caller.

UI behavior

Standalone GUI export shows exactly one result dialog. Warning summaries are aggregated by semantic code, while a bounded, resizable details control lists affected objects and resources. Log-only diagnostics never enter this summary. The persistent diagnostic log remains the owner of full technical context. Project persistence, canonical snapshots, and MVR-xchange remain non-modal and may inspect structured records according to their own policy; they do not log a second copy of exporter-owned diagnostics.

MVR node validity notes

Support is a standard MVR scene node and is preserved as <Support> during import/export; if geometry is missing, Perastage writes an empty <Geometries/> plus required ChainLength so the logical Support remains schema-valid without inventing model geometry. Generic <SceneObject> nodes require a <Geometries> child, so Perastage writes a small 10 cm placeholder cube when no source geometry is available instead of writing invalid XML. Truss children are emitted in XSD xs:sequence order, with Matrix before Geometries, fixture identifiers after geometry-related content, and CustomIdType before CustomId.

Standalone MVR and project fixture metadata

Standalone export and project scene.mvr now share the Perastage Canonical MVR contract documented in canonical_mvr_contract.md. Both include root-level ProjectFixtureMetadataMap, scoped by Data provider="Perastage" ver="1.0" and its own schemaVersion="1.0". Entries are sorted by canonical fixture UUID and preserve the editable fixtureId, fixtureIdNumeric, fixtureIdText, and unitNumber values independently from any interchange-only repair. They also preserve instance-owned visualColorHex values, including an explicit empty value through hasVisualColorHex="false", without applying one fixture's override to other fixtures of the same type.

ProjectFixtureMetadataMap is canonical Perastage scene-fidelity metadata, not project-container-only state. Supported metadata is recovered during project restore and standalone open/replace imports. Merge imports recover the imported fixture metadata and carry it through the existing UUID remapping, without changing unrelated fixtures already in the target scene. A valid instance entry overrides weaker type-level color metadata. The reader keeps the first successfully parsed identifier entry for a UUID; duplicate valid color metadata is diagnosed and the first value takes precedence. Malformed UUIDs and unsupported map or provider versions are diagnosed, invalid color values are ignored with diagnostics, incomplete identifier sets are ignored, and entries whose UUID does not identify an imported fixture are diagnosed. Data from foreign providers never gains authority over Perastage-owned fixture metadata.

Standard and compatibility truss geometry export

The parameterless exporter APIs, project scene.mvr, MVR-xchange, and canonical snapshots use CanonicalMvrExportOptions() and preserve the standard Symbol/Symdef truss representation when possible. File > Export MVR resolves the persisted standalone-export preference explicitly: Standard MVR representation uses that canonical policy, while Direct Geometry3D for truss symbols expands supported Symbol/Symdef geometry on the exporter's private scene copy. The latter is a standards-valid MVR 1.6 compatibility representation for applications with incomplete Symbol/Symdef support; it does not mutate or replace the canonical scene.

Invalid or missing visualColorHex values are ignored with the structured invalid_project_fixture_visual_color diagnostic. Standalone MVR identifier serialization treats FixtureID text independently from FixtureIDNumeric: duplicate numeric values are repaired to globally unique positive integers, while meaningful non-numeric text is preserved. Empty text and numeric fallback text follow the repaired numeric value. These standards-compliant exported substitutions do not overwrite project-owned identifiers when a .pstg project is restored, so intentional zero values and duplicate programming identifiers remain unchanged until the user edits them.

Symbol/Symdef UUID handling

MVR Symbol nodes represent geometry instances defined by a referenced Symdef. MVR 1.6 requires every exported Symbol to carry both a canonical uuid attribute for the symbol instance and a non-empty symdef reference. Perastage preserves an imported Symbol UUID when it is valid and belongs to preserved Symbol/Symdef geometry; if the original Symbol UUID is missing, invalid, or collides with another exported Symbol, Perastage derives a deterministic replacement from the container type, container UUID, Symdef UUID, Symbol matrix, and stable index context so repeated exports of the same scene remain logically stable.

MVR-xchange request/import behavior

Perastage can now request an advertised MVR revision from a compatible MVR-xchange TCP Mode station. The request uses the standard MVR_REQUEST message with the selected FileUUID, expects the peer to return an MVR file packet, writes the payload to a temporary .mvr file, and then runs the same MVR import policy used by File > Import MVR....

The dialog lists advertised remote revisions from the discovered station list so the user can choose the exact MVR file to request. Publishing still uses MVR_COMMIT announcements, while requesting/importing keeps the MVR payload unchanged and relies on the existing importer for project integration. After a payload is received, Perastage shows the normal import choice so users can open it as a new project or merge it into the current project.

Perastage binds the mDNS responder to the interface selected for the advertised MVR-xchange address. When multiple adapters exist on the same computer, select the same network interface in Perastage and the peer application so service discovery and TCP file exchange use the same local link.

Layer ownership and recovery

The serializer selects children by layerUuid and serializes every stored Layer UUID/name independently, including unnamed and equal-named layers. It uses the same path for the application default Layer. Import and legacy project loading repair identities in editable state; export recovery remains a defensive pass on the private preparation copy, not a mutation of the live scene. Valid source UUIDs survive import/edit/export without warning suppression. See Layer identity for the domain and migration contract.

Back to top