Table of Contents

Global Mapper (GM)

Global Mapper is a comprehensive Revit type-mapping tool that enables users to detect, plan, review, and commit bulk element replacements across families, types, materials, line styles, object styles, and shared parameters.

See also: Specification (Internal)

Overview

Global Mapper provides a unified interface for:

  • Family/Type Mapping: Replace family instances with equivalent types from other families
  • Duplicate Detection: Identify potential duplicate elements using similarity analysis
  • Usage Analysis: Understand material, line style, and object style usage across families
  • Deep Scan: Analyze family document contents to extract parameter names, style refs, and material refs
  • Shared Parameter Authoring: Bind and embed shared parameters to families/categories

Source: src/Tools/Common/GM/manifest.yml:1-26

Features

Feature Description
Duplicates Tab Detects potential duplicate families, materials, styles, and shared parameters using weighted similarity scoring. Tree nodes show aggregate resolved counts. Inspector pane uses Accept split button (Accept / Accept Once). Metadata expander shows SourceId and InstanceCount.
Families Tab Browse families by category, select target mappings, and configure type replacements
Line Styles Tab View and map line style usage with visual preview
Object Styles Tab View and map object style usage with visual preview
Materials Tab View and map material usage with color preview
Shared Parameters Tab Manage shared parameter bindings across categories and families
Cross-View Instance Navigation Families/SP instance cyclers zoom across views and activate/show the sampled instance
Plan + Commit Review Workflow Main window stages mappings, then Commit Review performs one explicit apply pass
Usage-Linked Family Apply Badges Families rows show OS, MAT, or OS+MAT when Apply is linked from Object Styles/Materials
Nested Usage-Link Indicators Expanded family Object Styles/Materials rows show LK badges (OS/MAT) for rows actively driving linkage
Usage-Link Planning Guardrail Usage-linked family Apply is impact-only; family-owned ops require explicit user ownership of the family row
Continue Refresh Pipeline Continue evicts stale family cache for active category, re-scans, refreshes usage data, and restores expanded detail context
Dual-Segment Status Bar Bottom-left status line renders Global + Active segments and updates live on tab/load/filter/mapping state changes
Load-Aware Empty States All GM tab empty placeholders use load-vs-empty messaging with high-contrast theme brushes
Deep Scan Analyze family documents to extract embedded parameter names, style references, and material references
Mapping Persistence Save and restore mapping targets per-project; restored rows keep Apply=false until user action
Conflict Detection Identify conflicting mappings (including parameter duplicate-target conflicts and type-write policy gating) before applying changes

Source: src/Tools/Common/GM/Shell/ViewModels/FamiliesPaneViewModel.cs:305
Source: src/Tools/Common/GM/Shell/ViewModels/SharedParametersPaneViewModel.cs:455
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:1358
Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:489
Source: src/Tools/Common/GM/Shell/ViewModels/MatchingModels.cs:190
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.UsageAndFamilies.cs:165
Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:4619
Source: src/Tools/Common/GM/Shell/Services/PlanBuildingService.cs:86
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:867
Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:814
Source: src/Tools/Common/GM/Shell/ViewModels/UsagePaneViewModel.cs:676
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.MappingInitAndInfrastructure.cs:487

Commit Review Lifecycle Guarantees

  • When opened, Commit Review builds and validates the plan only. No document edits run until the user clicks Apply.
  • Apply executes the normalized plan directly through IMappingService.ApplyPlanAsync(...), then runs verification in the same flow.
  • Overlay Cancel and Commit Review titlebar close both request cancellation and run graceful shutdown cleanup.
  • Overlay cancel wiring is direct (CancelButton.Click) and sets OverlayState.CancelRequested without throwing on transient DataContext swaps.
  • Cleanup waits for in-flight apply work to drain before allowing shutdown.
  • Apply emits explicit post-apply banners:
    • success banner with Applied/Failed/Skipped counts
    • failure banner beginning with Apply completed. (includes Failed/Skipped diagnostics) or Apply failed. on exceptions
  • Failed apply attempts keep the Commit Review window open so operation errors remain visible.
  • Plan building drops style pairs outside the active Line/Object style scopes and surfaces a warning banner instead of sending unsupported style operations to commit.
  • Style mappings are normalized to projection GraphicsStyle IDs before planning/commit so category-ID and style-ID variants resolve to the same operation target.
  • Object-style scope is explicitly constrained to Detail Items subcategories in both usage indexing and style-plan scope resolution.
  • Usage index hydration drops out-of-universe keys so tabs never render stale style/material IDs that are not in the current preview universes.
  • Style scope/normalization now uses a shared resolver in both plan and writer paths so accepted style mappings are classified identically during commit.
  • Style writer resolution now acquires the active host document through IRevitCallGate before classifying source/target style scope, removing ambient-context dependency during commit.
  • Scope-mismatch handling logs resolver reasons and explicit fallback acceptance details (line/object usage-backed) to make style commit failures root-cause traceable.
  • Material mappings are validated against host-document material existence during plan build; unresolved material pairs are dropped before commit with warning feedback.
  • Family reload phases for style/material/nesting/shared-parameter embed now execute through IRevitCallGate without opening a host-document transaction; LoadFamily is guarded to fail fast if the host document is modifiable.
  • Shared-parameter host/embed writers now require ISharedParameterAuthoringService from DI, eliminating silent no-op behavior when authoring dependencies are missing.
  • Shared-parameter plan building validates symbol-to-family ownership before emitting embed operations, rejecting stale/mismatched SP selections pre-commit.
  • While Commit Review is open, the GM main window is disabled (hard guarantee).
  • Accept + Continue runs a post-accept refresh pipeline:
    • removes the current category families snapshot from session cache
    • re-scans families and refreshes usage data
    • restores expanded family row-details context so instance cyclers remain available after refresh
  • Change apply engine is non-fail-fast across writer stages: writer failures are captured per operation and execution continues through remaining stages.
  • Commit Review now includes a full operation-results table (stable operation id, status, stage, source/target, timing, message) in addition to grouped failure summaries.
  • Apply results include per-phase timing metrics and total duration for Commit Review diagnostics.
  • Apply results now include per-domain summaries (stage-level succeeded/failed/skipped/affected plus family/timing context), surfaced in a dedicated Commit Review section.
  • Commit Review uses a staged TransactionGroup:
    • Apply begins a transaction group and executes apply + verify inside the group, then keeps the group open
    • Commit Review remains modal for the entire apply/accept/rollback session so the transaction group can remain open safely
    • Post-apply actions:
      • Rollback rolls back the transaction group (discard all changes from that apply session)
      • Accept + Continue assimilates the transaction group, closes Commit Review, and returns to GM
      • Accept + Close GM assimilates the transaction group, closes Commit Review, and closes GM

Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:267
Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:286
Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:548
Source: src/Tools/Common/GM/Shell/Views/CommitReviewWindow.xaml.cs:44
Source: src/Tools/Common/GM/Shell/Services/CommitReviewWindowService.cs:61
Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:274
Source: src/Tools/Common/GM/Shell/ViewModels/CommitReviewViewModel.cs:327
Source: src/Tools/Common/GM/Shell/Views/CommitReviewWindow.xaml.cs:60
Source: src/Tools/Common/GM/Shell/Views/CommitReviewWindow.xaml:318
Source: src/Tools/Common/GM/Features/Mapping/Writers/ChangeApplyEngine.cs:69
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.UsageAndFamilies.cs:236

User Interface

The GM window uses a Fluent Ribbon with six main tabs:

  1. Duplicates (Index 0) - Duplicate detection and resolution
  2. Families (Index 1) - Family/type mapping with category filtering
  3. Line Styles (Index 2) - Line style replacement with preview
  4. Object Styles (Index 3) - Object style replacement with preview
  5. Materials (Index 4) - Material replacement with color preview
  6. Shared Parameters (Index 5) - Parameter binding and authoring

Each tab provides:

  • A main DataGrid with source items and target selection dropdowns
  • Details-on-demand patterns (expanded row-details for Families, side details pane for Duplicates candidates)
  • Duplicates tab data-upfront summary band (counts, top offenders, next actions)
  • Nested row-details target columns that mirror top-level target rendering (read-only display + edit-time combobox)
  • Nested target default selection logic bound to global Sort Mode + Threshold
  • Parent family target changes trigger nested target-list repopulation for expanded rows (manual/saved/externally-originated selections remain sticky)
  • Open target dropdowns own mouse-wheel scrolling while hovered; wheel input does not fall through to the host DataGrid
  • Dropdown open/close without a logical selection change does not mark rows as user-edited; non-manual rows remain eligible for threshold/sort auto-selection recompute
  • Expanded family row usage tabs (Object Styles/Materials) hydrate after usage indices load and auto-refresh in-place for currently expanded/restored rows
  • Applied-only filtering keeps externally-originated rows and usage-linked family rows visible
  • Usage-pane "Families Using This..." apply indicators for Object Styles and Materials read canonical usage-link state, so indicator badges stay correct even when a referenced family is outside the current Families-tab row scope.
  • Empty placeholders are routed through shell-level load-aware message properties (loading vs zero-result copy per tab).
  • Visual previews where applicable (color swatches, style weights)
  • Action buttons for staging mappings and opening Commit Review
  • Duplicates threshold/sort/category changes rebuild from cached detection results (no duplicate re-scan)
  • Duplicates search/applied/kind-filter changes refresh through CollectionView.Filter (no source-row rebuild)
  • Duplicates family rows are category-scoped from the shared shell category selector, with an in-page selector bound to the same shell state
  • Duplicates source grid exposes explicit Apply checkboxes; Accept Applied and Applied Only both use Apply && HasKeepSelection
  • Duplicates detail panel exposes full exclusion lifecycle actions (Exclude, Override This Session, Remove Exclusion, Restore) and exclusion badges (timestamp tooltip from ExcludedAt when present)
  • Duplicates source rows are grouped by HasCandidates with explicit With Candidates / No Candidates group headers
  • Duplicates tab uses an internal kind filter (All, Families, Materials, Line Styles, Object Styles, Shared Params) and per-kind summary headers
  • Family duplicate rows can launch Edit Type Mapping... to populate _duplicateBatchTypeRules; modal options are similarity-scored and auto-select by threshold
  • Duplicates rebuilds preserve keep/apply state for all sources (including rows hidden by search/applied filters)
  • Shared-parameter candidate exclusions persist with stable type+name keys (not scan-local numeric IDs)
  • Shared-parameter duplicate keep/apply choices synchronize into Shared Parameters authoring rows (Map From + Apply) when no explicit user override exists
  • Duplicate conflict detection includes duplicate-vs-manual and duplicate multi-target (same source accepted to multiple targets) paths with bulk/single/auto resolution support
  • Choosing a non-duplicate winner for duplicate-vs-manual conflict resolution clears that duplicate source row's keep/apply state so row synchronization cannot immediately re-enable the conflicting pair
  • Usage-tab duplicate-origin badges are informational (non-click); override happens by editing the target selection directly

Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:621 Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:723 Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:814 Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:1467 Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:664 Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:885 Source: src/Tools/Common/GM/Shell/ViewModels/DuplicatesPaneViewModel.cs:1537 Source: src/Tools/Common/GM/Shell/ViewModels/DuplicatesPaneViewModel.cs:1572 Source: src/Tools/Common/GM/Shell/Services/MappingConflictService.cs:467 Source: src/Tools/Common/GM/Shell/ViewModels/DuplicatesModels.cs:211 Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml.cs:23 Source: src/DBTools.Themes/Behaviors/MouseWheelForwarder.cs:53 Source: src/DBTools.Core/UI/Behaviors/ComboBoxCommitCommandBehavior.cs:16

Global Header Controls

The header bar provides cross-tab controls:

  • Search: Filter visible items by name
  • Threshold Slider: Adjust similarity scoring threshold (0-100%)
  • Sort Mode: Toggle between Similarity and Alphabetical ordering
  • Filters: Hide Unused, Hide Unscanned, Applied Only

Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:600

Bottom Status Bar

  • Left status cell is a single-line composite string:
    • Global: family/usage/shared-parameter readiness snapshot
    • Active: current tab state (loading, visible rows, and apply-selected counts where applicable)
  • Conflict indicator button remains visible at all times and toggles conflict panel with current counts/summary.
  • Status updates on tab changes, load transitions, collection changes, and row-level mapping changes.
  • Toolbar filter visibility is tab-aware: "Applied Only" hides on Duplicates tab; "Hide Unscanned" shows only on Families and Shared Parameters tabs.

Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:867
Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:922
Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:4619 Source: src/Tools/Common/GM/Shell/Views/GmShellWindow.xaml:4369

Architecture

Module Structure

src/Tools/Common/GM/
+-- GmToolModule.cs            # DI module registration entry point
+-- manifest.yml               # Tool manifest (window + ribbon registration)
+-- Domain/                    # Kernel SSOT (ProjectState) + planning models
+-- Features/                  # Feature services (usage, mapping, duplicates, etc.)
|   +-- Caching/
|   +-- Categories/
|   +-- DeepScan/
|   +-- Duplicates/
|   +-- Families/
|   +-- Mapping/
|   +-- Previews/
|   +-- SavedMappings/
|   +-- SharedParameters/
|   +-- Similarity/
|   +-- Usage/
+-- Shell/                     # WPF shell (Views/ViewModels) + shell-level services
|   +-- Behaviors/
|   +-- Controls/
|   +-- Converters/
|   +-- Services/
|   +-- ViewModels/
|   +-- Views/
+-- Tests/                     # Unit tests + test support

Source: Directory structure of src/Tools/Common/GM/

Data Flow

                        +------------------+
                        |    GmCommand     |
                        +--------+---------+
                                 | Resolves services via DI
                                 v
                        +------------------+
                        | GmShellLauncher  |
                        +--------+---------+
                                 | Creates window + ViewModel
                                 v
                       +-------------------+
                       |   ShellViewModel  |
                       +--------+----------+
                                |
      +------------+------------+------------+------------+
      |            |            |            |            |
      v            v            v            v            v
+----------+ +----------+ +---------+ +----------+ +---------+
| Families | | Usage    | | Mapping | | Planning | | Kernel  |
| Pane VM  | | Pane VM  | | Service | | Service  | | State   |
+----------+ +----------+ +---------+ +----------+ +---------+

Kernel Architecture

The ProjectState is the Single Source of Truth (SSOT) for GM domain state. It holds IDs only - no Revit types leak into the kernel.

public sealed class ProjectState
{
    public long Version { get; set; }
    public SourceSnapshot? SourceSnapshot { get; set; }
    public Dictionary<int, FamilyRecord> Families { get; set; } = new();
    public UsageIndex Usage { get; set; } = new();
    public SharedParameterLedger SharedParameters { get; set; } = new();
    public TabStateSet Tabs { get; set; } = new();
    public Dictionary<int, string> FamilyNames { get; set; } = new();
    public Dictionary<int, string> SymbolNames { get; set; } = new();
    public Dictionary<int, IReadOnlyCollection<(string FamilyName, string SymbolName, int Count)>> NestedOwnerNameIndex { get; set; } = new();
}

Source: src/Tools/Common/GM/Domain/ProjectState.cs:10

The KernelMapper provides read-only projections of kernel data for UI consumption. All projections are version-aware and use a generic GetOrCompute<T> caching pattern:

  • GetLineStyleFamilyCounts() / GetObjectStyleFamilyCounts() / GetMaterialFamilyCounts() — Usage counts per style/material
  • GetObjectStylesByFamilyIndex() / GetMaterialsByFamilyIndex() — Reverse lookup: family → styles/materials
  • GetDeepScanStyleRefsByFamily() / GetDeepScanMaterialRefsByFamily() — DS references by family
  • GetDeepScanParamNamesByFamily() — DS parameter names by family

Source: src/Tools/Common/GM/Domain/KernelMapper.cs:54-221

Key Classes

Entry Points

Class File Purpose
GmToolModule src/Tools/Common/GM/GmToolModule.cs:8 Tool module registration; calls services.AddGm()
GmCommand src/Tools/Common/GM/Shell/GmCommand.cs:13 Ribbon command entry point; resolves all services and launches UI
GmShellLauncher src/Tools/Common/GM/Shell/GmShellLauncher.cs:17 Static launcher creating GmShellWindow and ShellViewModel

Source: src/Tools/Common/GM/GmToolModule.cs:8

View Models

Class File Purpose
ShellViewModel src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.*.cs Main shell view model (split across partials)
FamiliesPaneViewModel src/Tools/Common/GM/Shell/ViewModels/FamiliesPaneViewModel.cs Families tab bindings + commands
UsagePaneViewModel src/Tools/Common/GM/Shell/ViewModels/UsagePaneViewModel.cs Usage mapping workflows (matches, options, commands)
DuplicatesPaneViewModel src/Tools/Common/GM/Shell/ViewModels/DuplicatesPaneViewModel.cs Duplicates tab state
SharedParametersPaneViewModel src/Tools/Common/GM/Shell/ViewModels/SharedParametersPaneViewModel.cs Shared Parameters tab state

Source: src/Tools/Common/GM/Shell/ViewModels/FamiliesPaneViewModel.cs:1

Core Services

Interface Implementation Purpose
IProjectLifecycleService ProjectLifecycleService Build kernel from Revit document
IProjectQueries ProjectQueries Query kernel-backed domain views
IPlanningService PlanningService Generate normalized mapping plans
IMappingService MappingService Apply plans to Revit document (via ChangeApplyEngine)
IDuplicateDetectionService DuplicateDetectionService Detect duplicate elements
INamingSimilarityService NamingSimilarityService Name-based similarity scoring
IParameterSimilarityService ParameterSimilarityService Parameter overlap scoring

Source: src/Tools/Common/GM/Shell/Startup.cs:28

Revit Adapters (Change Writers)

All change writers implement IChangeWriter and are dispatched by ChangeApplyEngine via ChangeKind. Individual per-writer interfaces have been removed.

Implementation ChangeKind Purpose
TypeCreationService CreateTypes Create new type symbols in families
HostChangeService HostReplacements Replace host elements when type change requires recreation
NestingChangeService NestedFamilies Replace nested family instances by name
TypeChangeService TypeReplacements Replace type on instances; execute parameter migrations during type replacements
StyleChangeService StyleReplacements Replace line styles (host + family-doc rewrites, creates/syncs target subcategories)
MaterialChangeServiceWriter MaterialReplacements Replace materials (host + family-doc rewrites, creates/syncs target materials)
SharedParameterHostWriter SharedParametersHost Bind shared parameters to host document categories
SharedParameterEmbedWriter SharedParametersEmbed Embed shared parameters into family documents

Note: Deep scan is executed by DeepScanServiceAdapter (not a change writer).

Source: src/Tools/Common/GM/Features/Mapping/Writers/IChangeWriter.cs Source: src/Tools/Common/GM/Features/Mapping/Writers/ChangeApplyEngine.cs Source: src/Tools/Common/GM/Features/Mapping/Writers/StyleChangeService.cs Source: src/Tools/Common/GM/Features/Mapping/Writers/MaterialChangeServiceWriter.cs

Configuration

Manifest

id: DBTools.GM
assembly: DBTools
moduleType: DBTools.GM.GmToolModule
order: 0
sandboxWindows:
  - id: DBTools.GM.Main
    displayName: "Global Mapper"
    group: "Common"
    windowType: "DBTools.GM.Shell.Views.GmShellWindow"
    designTimeViewModelType: "DBTools.GM.Shell.DesignTime.ShellDesignTimeViewModel"
  - id: DBTools.GM.CommitReview
    displayName: "Global Mapper - Commit Review"
    group: "Common"
    windowType: "DBTools.GM.Shell.Views.CommitReviewWindow"
    designTimeViewModelType: "DBTools.GM.Shell.DesignTime.CommitReviewDesignTimeViewModel"
tool:
  ribbonTools:
    - internalName: DBTools.GM
      commandType: DBTools.GM.Shell.GmCommand
      availabilityType: DBTools.App.Availability.DocumentAvailability
      runProfile: QueuedModeless
      displayText: "Global Mapper"
      iconBaseKey: gm
      tooltip: "Open Global Mapper"
      controlKind: PushButton
      order: 30

Source: src/Tools/Common/GM/manifest.yml:1-26

Caching

GM uses caching strategies (some global, some document-scoped):

Cache Strategy Purpose
Deep Scan (global) DeepScanCacheStrategy Cache deep-scan results across sessions/documents (portable payload)
UI State (document-scoped) UiStateStrategy Persist UI selections between sessions
Saved Mappings (document-scoped) SavedMappingService Store user mapping preferences

Cache files are stored under %APPDATA%/DBTools/Cache/GM/.

Source: src/Tools/Common/GM/Shell/Startup.cs:108

API Reference

Planning Service

The IPlanningService generates normalized mapping plans:

public interface IPlanningService
{
    Task<PlanningResult> BuildPlanAsync(
        IReadOnlyDictionary<int, int> typeMappings,
        IReadOnlyDictionary<int, int> materialMappings,
        IReadOnlyDictionary<int, int> styleMappings,
        CancellationToken ct = default);

    Task<PlanningResult> BuildPlanAsync(
        IReadOnlyDictionary<int, int> typeMappings,
        IReadOnlyDictionary<int, int> materialMappings,
        IReadOnlyDictionary<int, int> styleMappings,
        IReadOnlyCollection<(int sourceId, string? newName)> createType,
        ProjectContext? context,
        CancellationToken ct = default);
}

Source: src/Tools/Common/GM/Domain/Planning/IPlanningService.cs:8

Operation Kinds

Plans contain operations of these types:

public enum OperationKind
{
    ReplaceType,          // Replace type on family instances
    ReplaceMaterial,      // Replace material parameters
    ReplaceStyle,         // Replace line/object styles
    MapParameter,         // Migrate parameter values during type replacements (explicit name mappings)
    AddNestedFamily,      // Add nested family replacement (by name)
    ReplaceHost,          // Handle host/placement mismatches
    CreateType,           // Create new type symbol
    BindSharedParameter,  // Bind SP at host level
    EmbedSharedParameter  // Embed SP in family document
}

Source: src/Tools/Common/GM/Domain/Planning/OperationKind.cs:3

Mapping Service

The IMappingService applies plans to the Revit document:

public interface IMappingService
{
    Task ImportAsync(string path, CancellationToken ct = default);
    Task ExportAsync(string path, CancellationToken ct = default);
    Task ImportSimpleAsync(string path, CancellationToken ct = default);
    Task ExportSimpleAsync(string path, CancellationToken ct = default);
    Task<MappingValidationResult> ValidateAsync(CancellationToken ct = default);
    Task<MappingApplyResult> ApplyAsync(CancellationToken ct = default);
    Task<MappingApplyResult> ApplyPlanAsync(PlanningResult plan, IProgress<(string message, double? progress01)>? progress = null,
        CancellationToken ct = default);
    Task<MappingVerifyResult> VerifyAsync(PlanningResult plan, CancellationToken ct = default);
    Task AddDuplicateMappingsAsync(DuplicateApplyBatch batch, CancellationToken ct = default);
}

Source: src/Tools/Common/GM/Features/Mapping/IMappingService.cs:12

Duplicate Detection

The IDuplicateDetectionService analyzes the kernel for potential duplicates:

public interface IDuplicateDetectionService
{
    Task<DuplicateDetectionResult> DetectAsync(
        ProjectState kernel,
        IProgress<string>? progress = null,
        CancellationToken ct = default);
}

Detection uses:

  • Families: 70% name similarity + 30% parameter overlap (when DS data available), with floor combined >= 0.5
  • Styles: Preview signature matching (color, weight, pattern), emitted as one directional pair set (i < j)
  • Materials: Preview + name similarity
  • Shared Parameters: Type display + normalized name
  • Family O(n^2) scan performs periodic cancellation checks
  • Detection reports progress stages (families, line-styles, object-styles, materials, shared-parameters) and VM maps these stages to overlay step deltas
  • DS badge origin tracking: rows display a DS badge when the duplicate was found using Deep Scan data; the ;ds=user rationale tag persists the origin

Source: src/Tools/Common/GM/Features/Duplicates/IDuplicateDetectionService.cs:7 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionProgressStages.cs:3 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:42 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:68 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:134 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:176 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:251 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:290 Source: src/Tools/Common/GM/Features/Duplicates/DuplicateDetectionService.cs:344 Source: src/Tools/Common/GM/Shell/ViewModels/DuplicatesPaneViewModel.cs:653

Testing

GM tests use a shared fixture that opens a dedicated test model:

[NonParallelizable]
public abstract class GmTestFixture
{
    protected const string GmModelFileName = "gm_test_model.rvt";
    protected UIApplication UiApp { get; private set; }
    protected Document? Doc { get; private set; }
    protected IRevitCallGate? Gate { get; private set; }
    protected ITransactionRunner? TxRunner { get; private set; }
}

Source: src/Tools/Common/GM/Tests/GMTestFixture.cs:20-53

Test Categories

Test Class Purpose
GM_PlanningServiceTests Planning result validation
GM_MappingServiceTests Apply/verify cycle testing
GM_MappingApplyPlanTests End-to-end plan application
DuplicateDetectionServiceTests Duplicate detection accuracy
GmKernelMapperTests Kernel projection correctness
GmWindowViewModel_*Tests ViewModel behavior tests

Running Tests

# Build test assemblies
bash build.sh BuildTests

# Run via Revit test runner
bash invoke-revit-tests.sh --smart --tool GM -y 2025

Troubleshooting

Common Issues

Issue Cause Resolution
"No families found" Category filter too restrictive Select a different category or clear filters
Empty duplicate groups Similarity threshold too high Lower the threshold slider
Deep scan incomplete Family document errors Check Revit error log; try manual deep scan
Mapping not applied Target type not available Verify target family is loaded in project
Conflict panel showing Multiple sources map to same target Resolve conflicts in conflict panel

Logging

GM logs diagnostic information via ILogger. Enable debug logging to see:

  • Kernel build timing
  • Cache hit/miss statistics
  • Plan operation details
  • Apply stage progress
_logger.LogDebug("GM: scanned {Count} families for categoryId={CategoryId}", 
    families.Count, SelectedCategory?.Id);

Source: src/Tools/Common/GM/Shell/ViewModels/ShellViewModel.CoreAndCommands.cs:1644


Verification Status

Check Status
Source anchors for all claims Yes
UNVERIFIED markers where needed No (all verified)
Cross-references added Yes
Examples tested N/A
No assumptions without evidence Yes

Verified by: docs-run-20260303-gm-refactor
Date: 2026-03-03