---
title: "How checks run"
description: "What runs when, why a rule that could not run is reported as unverified rather than passed, and what the runner does when a rule throws."
url: https://kaicad.barpom.xyz/docs/validation/how-checks-run
schema: "0.1"
source: packages/validate/src/index.ts
---

# How checks run

A compile is a pipeline, and validation is not a step at the end of it — findings are raised
at every stage and folded into one report.

```
design.yaml
   │  parse + schema         SCH-  is this a valid document?
   ▼
 resolve                     RES-  do the parameters, expressions and
   │                               catalogue IDs resolve?
   ▼
 assemble                    GEO-  where does every part actually end up?
   │
   ├──▶ takeoff              MFG-  can these parts be cut from real stock?
   │
   ├──▶ geometry (OCCT)      GEO-  do any two solids overlap, and by how much?
   │
   ▼
 validate                    FAS-  STR-  DOM-  PTH-
   │
   ▼
 one report
```

## A rule is one file

Every rule is a single pure function in its own file. It never imports another rule, never
mutates the design, and never reaches for the CAD kernel unless it declares that it needs
one. That is what makes the rule set something several people can extend at once without
collisions.

A rule that says "fastener too close to edge" has done half the job. Every finding carries:

- a **path** — a JSON Pointer into the document *you* wrote, not into some intermediate form
- a **suggestion** — computed: "move it to at least 12 mm from the edge"
- **detail** — the numbers behind the claim, so the report shows its working

## Severity is the rule's decision

The same condition is an error in one design and fine in another. A screw into end grain is a
warning in softwood and unremarkable in a bed bolt, because the bolt threads into steel.
Rules read the fixture's own constraints rather than hard-coding a severity.

## What did not run is part of the report

This is the part worth knowing before you cut anything.

- **`rulesPassed`** names every rule that ran and found nothing. That is evidence of
  coverage, and it is why a clean report is worth something.
- **Skipped rules are named, with a reason.** A rule that needs built geometry and did not
  get it is reported as **unverified**, never as passed. The difference matters more than any
  single finding.
- **A rule that throws does not take the report with it.** The other findings still arrive,
  and the crash is reported as a finding of its own.

## The codes are permanent

The code registry is append-only. A code that has been seen by someone's LLM, or counted in
an evaluation run, keeps meaning the same thing forever. Retiring a rule marks its code
retired; it never reuses the number.

[Every code, grouped by prefix](/docs/validation/error-codes).
