# How to Compare Two Diagram Snapshots in Archify: A Complete Guide to the Diff Engine

> Learn how Archify compares two diagram snapshots by exporting JSON states and calculating a client-side diff to reveal structural changes in your code.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: deep-dive
- Published: 2026-08-29

---

**Archify compares two diagram snapshots by exporting structured JSON graph states via `exportSnapshot()` and `reachabilitySnapshot()`, then computing a deterministic client-side diff of node IDs and edges to highlight structural changes.**

The `tt-a1i/archify` repository implements a client-side architecture visualization tool that enables engineers to analyze system topology and traffic patterns. When you need to compare two diagram snapshots in Archify, the platform executes a three-stage pipeline that captures graph states, computes differentials, and renders visual changes without requiring a server round-trip.

## The Three-Stage Comparison Pipeline

Archify’s snapshot comparison is architected as a pure data-driven diff that operates entirely within the browser. The process unfolds through distinct phases of data extraction, algorithmic comparison, and UI rendering.

### Stage 1: Exporting Structured Snapshots

The comparison begins by serializing the current graph state into a portable JSON format. Archify exposes specialized export methods depending on the lens context:

- **`Archify.routeProbe.exportSnapshot()`**: Captures the current route-focused view, including the ordered list of node IDs, edge arrays with `from` and `to` indices, hop counts, and source/target identifiers.
- **`Archify.focus.reachabilitySnapshot()`**: Exports reachability data for upstream or downstream analysis, containing directionality flags, depth parameters, and the subgraph’s node-edge topology.

Before any comparison occurs, Archify validates the exported payload. In [`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html) (lines 5805‑5811), the runtime verifies that the snapshot object contains the expected schema—specifically checking for the presence of `nodeIds` and `edges` arrays—to prevent malformed data from entering the diff engine.

### Stage 2: Computing the Differential

Once two snapshots are available, Archify’s core comparison algorithm executes a set-based diff on the graph structures:

1. **Edge Normalization**: The algorithm maps each snapshot’s edge array into normalized strings using `nodeIds` lookups (e.g., `${nodeIds[from]}→${nodeIds[to]}`), creating comparable edge signatures.
2. **Set Operations**: It constructs `Set` objects for both snapshots’ edges and performs intersection and difference operations to classify elements as added, removed, or unchanged.
3. **Semantic Filtering**: When the user selects the **Compare** lens with two semantic kinds, the diff limits results to direct authored links between those kinds. Selecting a single kind displays the full traffic pattern for that entity.

This approach ensures that even large architecture diagrams can be compared in milliseconds, as the complexity scales linearly with the number of edges rather than requiring expensive graph isomorphism calculations.

### Stage 3: Rendering the Visual Diff

The computed diff drives the visualization layer through specific UI hooks. In [`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html) (lines 6824‑6833), the codebase invokes `viewerCount('viewer.lens.compare', ...)` to update the interface with counts of changed elements.

The rendering engine applies data attributes such as `data-share-route` and `data-share-reach` to diagram nodes, enabling CSS to style additions, deletions, and unchanged elements with distinct visual treatments. Added edges typically render in highlight colors, removed edges are dimmed, and stable structures retain their standard styling.

## Key Source Files and Implementation Details

Several critical locations in the `tt-a1i/archify` repository define the snapshot comparison behavior:

- **[`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html)** (lines 5805‑5811): Validates route snapshots before they can be used in comparison operations, ensuring schema compliance.
- **[`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html)** (lines 6824‑6833): Implements the UI counters for the compare lens, displaying the volume of structural changes to the user.
- **`scripts/write-deterministic-zip.mjs`**: Ensures consistent file ordering in exported archives, which guarantees that snapshots produce identical checksums when no changes have occurred.
- **`scripts/package-smoke.mjs`**: Executes the `archify compare` command in the test harness, providing end-to-end validation of the snapshot diff functionality.

## Practical Implementation: Comparing Snapshots in Code

The following JavaScript demonstrates the client-side pattern for generating and comparing Archify snapshots:

```javascript
// Generate snapshots from the current viewer state
const routeSnapshot = Archify.routeProbe?.exportSnapshot?.();
const reachSnapshot = Archify.focus?.reachabilitySnapshot?.();

// Validate snapshot structure (as seen in mco-runtime.html)
function validateSnapshot(snap) {
  return snap 
    && Array.isArray(snap.nodeIds) 
    && Array.isArray(snap.edges)
    && snap.edges.every(e => typeof e.from === 'number' && typeof e.to === 'number');
}

// Compute differential between two snapshots
function compareSnapshots(snapA, snapB) {
  const normalizeEdge = e => `${snapA.nodeIds[e.from]}→${snapA.nodeIds[e.to]}`;
  const normalizeEdgeB = e => `${snapB.nodeIds[e.from]}→${snapB.nodeIds[e.to]}`;
  
  const setA = new Set(snapA.edges.map(normalizeEdge));
  const setB = new Set(snapB.edges.map(normalizeEdgeB));
  
  return {
    added: [...setB].filter(e => !setA.has(e)),
    removed: [...setA].filter(e => !setB.has(e)),
    unchanged: [...setA].filter(e => setB.has(e))
  };
}

// Update UI with comparison results
if (validateSnapshot(routeSnapshot) && validateSnapshot(reachSnapshot)) {
  const diff = compareSnapshots(routeSnapshot, reachSnapshot);
  viewerCount('viewer.lens.compare', diff.added.length + diff.removed.length);
  renderDiffOnDiagram(diff);
}

```

## Summary

- Archify’s comparison engine relies on **`exportSnapshot()`** and **`reachabilitySnapshot()`** methods to serialize graph states into standardized JSON structures.
- The diff algorithm operates client-side by comparing normalized edge signatures derived from `nodeIds` arrays, classifying changes as **added**, **removed**, or **unchanged**.
- Validation logic in [`mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/mco-runtime.html) (lines 5805‑5811) ensures data integrity before comparison, while UI counters (lines 6824‑6833) display the magnitude of detected changes.
- The system supports **semantic-kind filtering**, allowing comparisons to focus on specific relationship types when two kinds are selected in the compare lens.
- All processing occurs **without server dependencies**, making the tool suitable for offline analysis of sensitive architecture diagrams.

## Frequently Asked Questions

### What data structure does an Archify snapshot use?

An Archify snapshot is a plain JavaScript object containing an array of `nodeIds` (strings) and an `edges` array where each element specifies `from` and `to` indices that reference positions in the `nodeIds` array. Route snapshots additionally include `hop`, `source`, and `target` properties, while reachability snapshots contain `direction` and `depth` metadata.

### How does Archify validate snapshots before comparison?

According to the source code in [`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html) (lines 5805‑5811), the validation routine checks that the input is a non-null object containing array properties for `nodeIds` and `edges`, and verifies that every edge object has numeric `from` and `to` properties. This schema validation prevents runtime errors during the diff computation.

### Can Archify compare snapshots from different diagram types?

Yes, provided both snapshots conform to the expected schema. The comparison algorithm is agnostic to the semantic meaning of the diagram; it only compares the graph topology (nodes and edges). However, the **Compare** lens in the UI may filter results to show only direct links between selected semantic kinds, which could yield empty results if the snapshots contain no overlapping relationship types.

### Where is the comparison logic located in the source code?

The core comparison routines are implemented in [`experiments/mco-showcase/mco-runtime.html`](https://github.com/tt-a1i/archify/blob/main/experiments/mco-showcase/mco-runtime.html), specifically around lines 6824‑6833 where the `viewerCount` function handles the compare lens counts. The underlying snapshot generation methods are attached to the global `Archify` object (via `routeProbe` and `focus` namespaces), while build-time consistency checks reside in `scripts/write-deterministic-zip.mjs` and `scripts/package-smoke.mjs`.