# Archify Compare Command: Rollback Path and Atomic Commit Explained

> Learn how Archify's compare command ensures safe architecture updates with atomic commit and automatic rollback on failure. Keep your projects secure.

- Repository: [tt-a1i/archify](https://github.com/tt-a1i/archify)
- Tags: how-to-guide
- Published: 2026-08-31

---

**The Archify CLI ensures safe architecture updates by validating artifacts before any file system changes, then committing atomically with automatic rollback on failure.**

Archify is a CLI-driven visual-architecture engine that treats infrastructure diagrams as versioned artifacts. The `compare` command sits at the heart of its delivery workflow, enabling teams to diff architecture changes, validate receipt integrity, and commit updates—or fully reverse them—without leaving the system in a partial state. This article breaks down how the compare command's rollback path and atomic commit mechanism work together to prevent corrupted deployments.

## How the Archify Compare Command Works

The `compare` command in `archify/bin/archify.mjs` takes two architecture artifacts—an HTML rendering and a receipt JSON—and produces a validated diff ready for commit. The CLI entry point delegates to `compareComparePair`, which orchestrates the entire workflow from parsing through potential rollback.

The command structure follows this pattern:

```bash
node bin/archify.mjs compare path/to/prev.html path/to/next.html

```

Under the hood, Archify extracts `htmlCandidate` and `receiptCandidate` from the provided paths, then subjects them to strict validation before any permanent changes occur.

## Pre-Commit Validation: The Fail-Fast Gate

Before touching the file system, Archify validates the receipt JSON against multiple criteria:

- `completeness === 'complete'` — ensures the architecture generation finished
- `checksPassed === checkCount` — confirms all quality gates passed

This validation lives early in `archify/bin/archify.mjs` (around line 677). If any check fails, the process aborts immediately with no side effects. This **fail-fast design** guarantees that invalid artifacts never reach the commit phase.

The validation step is critical for atomicity: by catching errors before the first write, Archify eliminates the need to undo partial work from malformed inputs.

## Atomic Commit Implementation in commitComparePair

Once validation succeeds, control passes to `commitComparePair`, also defined in `archify/bin/archify.mjs`. This function implements true atomicity through a staged commit pattern:

```javascript
async function commitComparePair({ htmlCandidate, receiptCandidate, outputPath, receiptPath }) {
  const committed = [];

  // Write the new HTML
  await fs.promises.writeFile(outputPath, htmlCandidate);
  committed.push({ label: 'HTML', path: outputPath });

  // Write the new receipt
  await fs.promises.writeFile(receiptPath, receiptCandidate);
  committed.push({ label: 'Receipt', path: receiptPath });
}

```

The `committed` array serves as a **transaction log**. Every successful write is recorded with its label and path, enabling deterministic reversal if subsequent operations fail.

### Staging and Finalization Strategy

While the simplified snippet above writes directly to target locations, the full implementation uses staging directories where possible, then performs atomic moves. This minimizes the window where files exist in an inconsistent state.

## Automatic Rollback on Commit Failure

The rollback mechanism activates when any file operation throws. The catch block in `commitComparePair` implements reverse-order cleanup:

```javascript
} catch (e) {
  const rollbackErrors = [];
  for (const item of [...committed].reverse()) {
    try { await fs.promises.unlink(item.path); }
    catch (err) { 
      rollbackErrors.push(`${item.label}: remove failed (${err.message})`); 
    }
  }
  // Surface error with rollback details
}

```

**Key implementation details:**

- Iteration in `reverse()` order ensures dependency-sensitive cleanup (remove receipt before HTML if receipt depends on HTML location)
- Each rollback attempt is wrapped in individual try/catch to continue past non-critical failures
- Accumulated `rollbackErrors` provides complete visibility into what succeeded and what didn't

## Error Taxonomy and Failure Modes

Archify distinguishes between two failure states with distinct error codes:

| Error Code | Meaning | When It Occurs |
|---|---|---|
| `delta/commit-failed` | Write operation failed, but rollback succeeded | Initial `fs.writeFile` or `fs.rename` throws, all `committed` items removed |
| `delta/commit-rollback-failed` | Write failed **and** rollback partially or fully failed | Cleanup of `committed` items encountered errors, system may be in inconsistent state |

This explicit taxonomy, defined in `archify/bin/archify.mjs`, enables operators to quickly assess severity and determine manual intervention needs.

## Visualizing the Rollback Path: Exception Lanes in Architecture Diagrams

Archify's visual output reinforces the rollback concept through dedicated **exception lanes** in workflow diagrams. The workflow definition in [`archify/examples/deployment-release.lifecycle.json`](https://github.com/tt-a1i/archify/blob/main/archify/examples/deployment-release.lifecycle.json) shows this structure:

- Node `"id":"rollback"` with `"lane":"exceptions"`
- Edge `"from":"ready" to "rollback"` marked `"variant":"security"`

These visual elements serve two purposes:

1. **Engineering clarity** — developers see recovery paths as first-class workflow components
2. **Auditability** — reviewers can trace exactly where and how the system returns to known-good states

The UI layer (`viewer.lens.compare` and related scripts) highlights the rollback node, making the recovery path instantly identifiable in generated guides.

## Practical Examples: Running Compare and Triggering Rollback

### Successful Compare and Commit

```bash

# Compare an architecture to itself (demo mode)

node bin/archify.mjs compare \
    examples/deployment-release.lifecycle.html \
    examples/deployment-release.lifecycle.html

```

This executes the full validation and commit path when the receipt validates successfully.

### Provoking Rollback for Testing

```bash

# Point to a non-existent receipt to trigger failure

node bin/archify.mjs compare \
    examples/deployment-release.lifecycle.html \
    missing/receipt.json

```

Expected output includes error code `delta/commit-failed` or `delta/commit-rollback-failed` with populated `rollbackErrors` array detailing cleanup results.

## Integration with Smoke Testing

The `scripts/package-smoke.mjs` harness exercises the compare command in CI pipelines. It:

1. Generates architecture artifacts
2. Invokes `compare` with validation enabled
3. Asserts receipt integrity
4. Verifies rollback behavior through intentional failure injection

This ensures the rollback path remains functional across releases.

## Related Components and Test Coverage

| File | Responsibility | Rollback Relevance |
|---|---|---|
| `archify/test/guide.test.mjs` | Unit tests for generated guides | Verifies rollback nodes appear in visual output |
| `archify/recipes/scenarios.mjs` | High-level scenario definitions | Includes "rollback" as a recoverable signal type |
| [`archify/examples/deployment-release.lifecycle.json`](https://github.com/tt-a1i/archify/blob/main/archify/examples/deployment-release.lifecycle.json) | Example workflow | Demonstrates exception lane structure |

## Summary

- **Fail-fast validation** in `archify/bin/archify.mjs` prevents invalid artifacts from reaching the file system
- **Atomic commit** via `commitComparePair` uses a `committed` transaction log for deterministic writes
- **Automatic rollback** reverses successful operations in reverse order when failures occur
- **Explicit error codes** (`delta/commit-failed` vs `delta/commit-rollback-failed`) clarify recovery needs
- **Visual exception lanes** in workflow diagrams make rollback paths auditable and reviewable

## Frequently Asked Questions

### How does Archify ensure no partial state during a failed compare?

Archify validates all inputs before the first file write, then records every successful operation in the `committed` array. If any subsequent write fails, the catch block iterates through `committed` in reverse order and removes each file. This guarantees either complete success or complete reversion—no intermediate states persist.

### What is the difference between delta/commit-failed and delta/commit-rollback-failed?

`delta/commit-failed` means the initial commit operation failed but cleanup succeeded—the system returned to its original state. `delta/commit-rollback-failed` indicates a more serious condition where both the commit and the subsequent rollback encountered errors, potentially leaving the system in an inconsistent state requiring manual intervention.

### Where is the rollback path visually defined in Archify workflows?

The rollback path appears as an exception lane in workflow JSON files like [`archify/examples/deployment-release.lifecycle.json`](https://github.com/tt-a1i/archify/blob/main/archify/examples/deployment-release.lifecycle.json). Look for nodes with `"lane":"exceptions"` and edges connecting failure states to the rollback node. The UI layer renders these in a distinct visual style to highlight recovery routes.

### Can I test the rollback behavior without modifying source code?

Yes. Invoke `node bin/archify.mjs compare` with a non-existent receipt path or invalid JSON. This triggers validation or commit failure and exercises the full rollback mechanism. The `scripts/package-smoke.mjs` harness includes automated tests that verify this behavior in CI environments.