Concepts
One canonical model
The governing invariant and what it costs to hold.
There is exactly one canonical model: the Engineering Intermediate Representation. The kernel graph is its live realization. Everything else is a lowering of it, a projection of it or an interchange encoding of it. That covers a netlist, a view, a SPICE deck and a KiCad file.
No feature may introduce a second persisted representation of the same facts.
Why it is stated as a prohibition
Section titled “Why it is stated as a prohibition”Most hardware toolchains fail in the same place. The schematic, the BOM and the simulation deck each hold their own copy of the same facts, and each copy was true when it was written. Reconciling them becomes the work. The invariant removes that work by leaving nothing to reconcile.
The cost is real. A downstream tool that wants its own store cannot have one. It
gets a generated Projection and recomputes, which is slower. A cache that can
go stale is a second representation.
How it is enforced
Section titled “How it is enforced”ConstraintRegistry enforces it literally. Constructing a second registry for a
project raises ELAB-0012:
ConstraintRegistry(project) # fineConstraintRegistry(project) # ELAB-0012: a second constraint registry was createdThere is no flag to allow it.
What the model holds
Section titled “What the model holds”Sixteen entity kinds, each a frozen dataclass carrying identity, parameters, provenance and a source location:
| Group | Kinds |
|---|---|
| Structure | Component, Net, Rail, Connection, Domain |
| Interfaces | Interface, Port, Bus, Pin |
| Rationale | Requirement, Decision, Evidence, Calculation, Verification, Assumption |
| Analysis | Model |
Every entity answers two questions. references() drives referential integrity,
diff impact and topology adjacency. as_dict() drives canonical serialization.
A new entity kind that does not answer both cannot participate in the graph.
Identity
Section titled “Identity”An identifier is a UUIDv5 over (project namespace, "<kind>:<canonical semantic path>"), rendered as a prefix plus twelve hex digits. Two consequences matter
in practice.
Re-derivation is stable. The same design gives the same identifiers, in this process or another one. Identifiers are not allocated from a counter, so there is no allocation order to preserve.
Collisions lengthen rather than renumber. An identifier is extended four digits at a time, only against the identifiers already in that revision, so lengthening is itself reproducible.
Three origins exist and are distinguished: derive() for a fact the kernel
computed, authored() for one a person wrote and imported() for one that came
from CAD.
Determinism
Section titled “Determinism”Identical inputs give byte-identical snapshots. This is verified across
processes with differing PYTHONHASHSEED, not merely within one run.
Two rules make that hold. Magnitudes are Decimal strings under a fixed
Context(prec=34), never binary floats, so no value depends on rounding mode.
And canonical serialization sorts by Unicode code point, except for the
collections in serialization.ORDERED_COLLECTIONS, whose order carries meaning
and is preserved.