# Source Hash and Validation Systems for CAD Artifacts in Text‑to‑CAD

> Learn how Text-to-CAD ensures CAD artifact integrity. Discover SHA-256 source hashes and validation systems that prevent stale files and schema mismatches in the earthtojake/text-to-cad repository.

- Repository: [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad)
- Tags: architecture
- Published: 2026-08-01

---

**The Text‑to‑CAD repository implements a dual-layer integrity system that computes SHA‑256 source hashes for every CAD file and validates them against embedded metadata to detect stale artifacts and schema mismatches.**

The earthtojake/text-to-cad project treats every generated artifact—from STEP and STL to GLB and URDF—as a versioned, verifiable object. Understanding the source hash and validation systems for CAD artifacts is essential for maintaining consistency across the generation pipeline and ensuring that downstream consumers always receive current, uncorrupted geometry.

## How Source Hashes Work

The source hash is a deterministic SHA‑256 fingerprint of the original file embedded directly into artifact metadata. This allows the system to detect when a generated GLB or other derived format no longer matches its underlying source.

### Computing the Hash

The utility function `sha256File()` in `viewer/src/server/catalog/cadDirectoryScanner.mjs` (lines 45‑61) streams the file and produces a 64‑character hexadecimal hash:

```javascript
import { sha256File } from 'viewer/src/server/catalog/cadDirectoryScanner.mjs';

const hash = await sha256File('/models/parts/bracket.step');
// Returns: 'a3f5c8...64 chars...'

```

### Embedding Hash Metadata

During GLB generation, the hash is written to the GLB extension under `manifest.sourceHash`. The Python generator in [`packages/cadpy_metadata/src/cadpy_metadata/generator.py`](https://github.com/earthtojake/text-to-cad/blob/main/packages/cadpy_metadata/src/cadpy_metadata/generator.py) populates this field from comment metadata (`<!-- cadpy:sourceHash=… -->`), while the Node.js compiler in `viewer/src/server/step/stepArtifactCompiler.mjs` orchestrates the injection:

```javascript
// From stepArtifactCompiler.mjs
const metadata = {
  sourcePath: relativeSourcePath,
  sourceHash: await sha256File(sourcePath),
  stepHash: await sha256File(stepPath)
};

```

### Reading Stored Hashes

The `validateStepTopologyArtifact()` function extracts the stored hash from `manifest.sourceHash` and recomputes the current hash of the underlying STEP file (`currentStepHash`) for comparison.

## The Validation Pipeline

The validation system enforces a strict sequence of checks that return structured results containing `ok`, `error`, `hash`, `sourceKind`, and other metadata. Any failure returns a machine‑readable error code and human‑readable message.

### Step‑by‑Step Validation Sequence

1. **Locate the artifact** – `inlineStepGlbArtifactPathForSource(sourcePath)` builds the path to the inline GLB.
2. **Check existence** – Returns `missing_glb` if the file is absent.
3. **Parse the container** – `readGlbTopologyContainer()` (lines 105‑155) verifies the GLB header and extracts the JSON chunk.
4. **Validate STEP topology extension** – Checks for `STEP_topology` extension (`missing_step_topology`) and correct schema version (`STEP_TOPOLOGY_SCHEMA_VERSION`, returns `unsupported_step_topology` if mismatched).
5. **Validate source identity** – Verifies `sourcePath` exists in manifest (`missing_source_path` if absent).
6. **Validate hash consistency** – Compares stored `stepHash` against freshly computed SHA‑256 of the STEP file, returning `stale_step_artifact` on mismatch or `missing_step_hash` if the field is absent.
7. **Validate topology views** – Ensures edge topology (`STEP_EDGE_BARYCENTRIC_ATTRIBUTE`, `STEP_EDGE_CLASS_ATTRIBUTE`) and selector views conform to schema, returning `missing_edge_topology` or `missing_selector_topology` if required attributes are absent.

### Validation Result Structure

On success, `validateStepTopologyArtifact()` returns:

```javascript
{
  topology,               // parsed STEP topology description
  stepArtifact: { 
    ok: true, 
    sourceKind, 
    sourcePath, 
    glbPath, 
    ... 
  },
  glbPath,
  stepHash,
  sourceHash,
}

```

On failure, `stepArtifact.ok` is `false` and includes a detailed `error` object with `code` and `message`.

## Key Implementation Files

| File | Role |
|------|------|
| `viewer/src/server/catalog/cadDirectoryScanner.mjs` | Implements `sha256File`, `validateStepTopologyArtifact`, and `readStepSourceStatus` |
| `viewer/src/server/step/stepArtifactCompiler.mjs` | Orchestrates GLB generation and metadata injection |
| `viewer/src/server/step/stepMetadata.mjs` | Parses CAD‑specific comment metadata (`<!-- cadpy:sourceHash=… -->`) |
| [`packages/cadpy_metadata/src/cadpy_metadata/generator.py`](https://github.com/earthtojake/text-to-cad/blob/main/packages/cadpy_metadata/src/cadpy_metadata/generator.py) | Python‑side hash computation and GLB manifest population |
| [`viewer/src/client/workbench/fileStatusItems.js`](https://github.com/earthtojake/text-to-cad/blob/main/viewer/src/client/workbench/fileStatusItems.js) | Maps validation error codes to UI messages |

## Practical Usage Examples

### Validate a STEP File Programmatically

Use `validateStepTopologyArtifact()` to verify a generated GLB matches its source:

```javascript
import { validateStepTopologyArtifact } from
  'viewer/src/server/catalog/cadDirectoryScanner.mjs';

const result = validateStepTopologyArtifact({
  repoRoot: '/path/to/repo',
  sourcePath: '/models/parts/bracket.step',
  cadPath: 'parts/bracket.step'
});

if (result.stepArtifact.ok) {
  console.log('✅ GLB is up‑to‑date');
} else {
  console.error('❌ Validation failed:', result.stepArtifact.error);
}

```

### Inspect Embedded Source Hashes

Extract the `sourceHash` from a generated GLB:

```javascript
import { readStepCatalogMetadata } from
  'viewer/src/server/catalog/cadDirectoryScanner.mjs';

const meta = readStepCatalogMetadata({
  repoRoot: '/path/to/repo',
  glbPath: '/models/parts/.bracket.step.glb'
});
console.log('Source hash:', meta.sourceHash);

```

### Python Generator Integration

Embed hashes when generating artifacts:

```python

# packages/cadpy_metadata/src/cadpy_metadata/generator.py

def generate_step(source_path: Path, output_glb: Path):
    # ... generate geometry ...

    metadata = {
        "sourcePath": str(source_path.relative_to(repo_root)),
        "sourceHash": compute_sha256(source_path),
        "stepHash": compute_sha256(step_file),
    }
    embed_metadata_into_glb(output_glb, metadata)

```

## Summary

- **Source hashes** are SHA‑256 fingerprints computed by `sha256File()` and embedded in GLB metadata under `manifest.sourceHash`.
- **Validation** occurs through `validateStepTopologyArtifact()`, which checks file existence, schema versions (`STEP_TOPOLOGY_SCHEMA_VERSION`), hash consistency, and required topology attributes.
- **Error codes** like `stale_step_artifact` and `missing_step_hash` provide precise diagnostics for CI/CD pipelines and viewer UIs.
- The system spans both Node.js (`cadDirectoryScanner.mjs`, `stepArtifactCompiler.mjs`) and Python ([`generator.py`](https://github.com/earthtojake/text-to-cad/blob/main/generator.py)) to ensure end‑to‑end integrity.

## Frequently Asked Questions

### What happens when a STEP file changes but the GLB is not regenerated?

The validator returns a `stale_step_artifact` error because the stored `stepHash` in the GLB metadata no longer matches the recomputed SHA‑256 of the current STEP file. This prevents downstream tools from using outdated geometry.

### Where is the source hash actually stored inside a GLB file?

According to `viewer/src/server/step/stepArtifactCompiler.mjs`, the hash is written to the GLB’s JSON chunk under the extension key `manifest.sourceHash`. Python‑generated artifacts insert this via the `cadpy_metadata` package as a comment that gets parsed into the same structure.

### Can I validate artifacts without loading the full GLB into memory?

Yes. Use `readStepSourceStatus()` in `viewer/src/server/catalog/cadDirectoryScanner.mjs`, which provides a lightweight wrapper around the validation logic suitable for quick checks in CLI tools and file watchers.

### What error code indicates a schema version mismatch?

If the GLB’s `STEP_topology` extension exists but uses an outdated schema version, the validator returns `unsupported_step_topology`. The expected version is defined by the constant `STEP_TOPOLOGY_SCHEMA_VERSION` in the scanner module.