How Archify's Validation System Works: Schema Checks and Composition Checks Explained

Archify validates every architecture diagram in two independent stages—schema validation against a JSON-IR type system, followed by geometric composition checks on the rendered SVG—producing a validation receipt that powers CI gates and proof galleries.

Archify's validation system ensures that authored diagrams meet both structural and visual quality standards before they reach production. The system is implemented across archify/renderers/shared/validator.mjs and archify/renderers/shared/geometry.mjs, with the CLI at archify/bin/archify.mjs orchestrating the full pipeline. This article breaks down how both validation stages work and what each composition check evaluates.


Schema Validation: Type-Safe JSON-IR Verification

The first stage ensures your diagram data conforms to the expected structure for its type. This check is fail-closed: any schema error aborts the pipeline immediately.

How Schema Validation Runs

  1. Load the validatorvalidateSchema(diagramType, data) imports the pre-compiled AJV function from archify/renderers/shared/generated-validators.mjs.
  2. Execute AJV – The validator runs against your diagram's JSON-IR. If validate(data) returns false, AJV populates validate.errors.
  3. Format diagnosticsformatErrors builds human-readable messages, while annotatedPath enriches JSON pointers with node identifiers (e.g., /nodes/3 (id: "router")/label).
  4. Abort on failurethrowDiagnosticError creates a structured diagnostic object with code, severity, subject, evidence, and supportedFixes, then halts execution.

The schema validator is deterministic and environment-independent—it is compiled ahead of time and bundled with the package.

Running Schema Validation Programmatically

import { validateSchema } from './archify/renderers/shared/validator.mjs';
import fs from 'fs';

const diagram = JSON.parse(fs.readFileSync('my-diagram.json'));
try {
  validateSchema('workflow', diagram);   // throws on any schema error
  console.log('✅ Schema OK');
} catch (err) {
  console.error('❌ Schema validation failed:', err.diagnostics);
}

Composition Checks: Geometric Quality Validation

After the deterministic renderer produces SVG geometry, Archify extracts attributes like data-composition-points and data-composition-frame-* to run geometric composition checks. These evaluate visual quality and structural soundness. All checks are implemented in archify/renderers/shared/geometry.mjs.

The Eight Composition Checks

Check Measurement Severity Behavior
Proper crossing X-shaped edge intersections Warning in showcase profile, error in standard
Ambiguous corridor Overlapping parallel edge segments that create indistinguishable paths Warning or error depending on profile
Label route clearance Minimum distance between relationship label routes and intersecting components Warning or error
Container-border runs Edge crossings of structural frame borders (regions, groups, lanes) Warning or error when excessive
Short interior segment Edge segments shorter than segmentPx threshold Warning or error
Micro segment Sub-pixel segments below microSegmentPx that cause rendering artifacts Warning only
Bend count & stretch Route complexity metrics—maximum bends, routes over suggested bend count, overall stretch Used for rhythm profile
Metrics aggregation Normalized summary via routeBudgetMetrics including all counts and suggestedLimits per profile Summary output

Key Functions in geometry.mjs

  • collectAmbiguousCorridors()cleanAmbiguousCorridorProblems()
  • collectBorderRuns()cleanBorderRunProblems()
  • collectLabelRouteClearance()cleanLabelRouteClearanceProblems()
  • routeBudgetMetrics() – returns aggregate statistics and threshold guidance

Each collect* function gathers raw geometry; each clean*Problems function transforms that data into structured issue objects with code, severity, message, and optional threshold.

Running Composition Checks Programmatically

import {
  collectAmbiguousCorridors,
  cleanAmbiguousCorridorProblems,
  collectBorderRuns,
  cleanBorderRunProblems,
  collectLabelRouteClearance,
  cleanLabelRouteClearanceProblems,
  routeBudgetMetrics
} from './archify/renderers/shared/geometry.mjs';

const svg = parseSVG(fs.readFileSync('my-diagram.svg'));
const composition = {};

composition.ambiguousCorridors = cleanAmbiguousCorridorProblems(
  collectAmbiguousCorridors(svg)
);
composition.containerBorderRuns = cleanBorderRunProblems(
  collectBorderRuns(svg)
);
composition.labelRouteClearance = cleanLabelRouteClearanceProblems(
  collectLabelRouteClearance(svg)
);
composition.metrics = routeBudgetMetrics(svg);

console.log('Composition summary:', composition);

The Validation Receipt: Merging Results

The CLI merges schema and composition results into a single validation receipt (receipt.validation) written alongside each rendered artifact.

Receipt Structure

{
  ok: boolean,                          // true if both stages pass
  checksPassed: number,
  checkCount: number,
  compositionProfile: 'showcase' | 'standard' | 'rhythm',
  compositionStatus: 'pass' | 'fail',   // pass = warnings only, no errors
  composition: {
    issues: [/* issue objects */],
    metrics: { /* routeBudgetMetrics output */ }
  }
}

Status determination: compositionStatus is pass only when every issue has "warning" severity. Any "error" flips it to fail. The compositionProfile is derived from the rendering profile.

CLI Output Example

9/9 artifact checks; composition showcase: PASS·SHA256 a1b2c3…

scripts/build-gallery.mjs injects receipt data into HTML proof galleries:

<div class="receipt-cell">
  <span class="receipt-label">Composition</span>
  <span class="receipt-value ok"
        title="1 crossings · 0 border runs · 0 micro segments · 0 cramped turns">
    SHOWCASE · PASS
  </span>
</div>

Full Validation Pipeline in Code

This illustrates what archify/bin/archify.mjs executes internally:

import { validateSchema } from './archify/renderers/shared/validator.mjs';
import { runCompositionChecks } from './archify/renderers/shared/geometry.mjs';

function createReceipt(diagramType, diagram, renderedSvg) {
  // 1️⃣ Schema validation
  try {
    validateSchema(diagramType, diagram);
  } catch (e) {
    return { ok: false, schema: e.diagnostics };
  }

  // 2️⃣ Composition validation
  const composition = runCompositionChecks(renderedSvg);

  // 3️⃣ Aggregate receipt
  const checksPassed = composition.issues.filter(i => i.severity === 'warning').length;
  const checkCount = composition.issues.length;

  return {
    ok: composition.status === 'pass',
    checksPassed,
    checkCount,
    compositionProfile: composition.profile,
    compositionStatus: composition.status,
    composition,
  };
}

Profile-Based Severity Mapping

Profile Purpose Strictness
showcase Highest visual quality, publication-ready Warnings for most issues
standard Production diagrams Errors for crossings, corridors, clearance
rhythm Emphasizes clean routing cadence Errors for excessive bends or stretch

The routeBudgetMetrics function provides suggestedLimits objects describing thresholds for each profile, enabling profile-aware CI gates.


Summary

  • Schema validation in archify/renderers/shared/validator.mjs provides fail-closed type checking using pre-compiled AJV validators from generated-validators.mjs.
  • Composition checks in archify/renderers/shared/geometry.mjs evaluate eight geometric quality criteria including crossings, corridors, label clearance, and border runs.
  • Validation receipts merge both stages into receipt.validation, consumed by the CLI, gallery scripts (scripts/build-gallery.mjs), and CI gates (scripts/package-smoke.mjs).
  • Profile-driven severity allows showcase, standard, and rhythm modes to tune strictness for different output contexts.

Frequently Asked Questions

What happens if schema validation fails?

The pipeline aborts immediately. throwDiagnosticError creates structured diagnostics with annotated JSON pointers, and no SVG is rendered. This fail-closed design prevents invalid data from reaching composition checks.

How does Archify detect ambiguous corridors?

The collectAmbiguousCorridors function in geometry.mjs identifies overlapping parallel edge segments that create visually indistinguishable paths. cleanAmbiguousCorridorProblems converts these into issue objects with severity determined by the active composition profile.

Can I run validation without using the CLI?

Yes. Import validateSchema and the composition helpers directly from archify/renderers/shared/validator.mjs and geometry.mjs to build custom pipelines. The receipt format documented above is stable for下游 tooling.

What's the difference between warnings and errors in composition checks?

Errors fail the composition stage (compositionStatus: 'fail'), while warnings allow it to pass. The threshold for each check varies by profile—standard and rhythm promote more warnings to errors than showcase.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →