Compile-time edge validation#

MADDENING v0.2 added a graph-edge consistency check. Every edge wires one node’s output field to another node’s BoundaryInputSpec; the check flags edges whose two ends disagree.

What it checks#

For each edge, GraphManager.validate() compares the source field against the target node’s boundary_input_spec() entry on three axes:

  • shape — source array shape vs. BoundaryInputSpec.shape.

  • dtype — source array dtype vs. BoundaryInputSpec.dtype.

  • units — the edge’s declared source_units / target_units vs. the spec’s expected_units.

Shape and dtype checks are skipped when the edge carries a transform (which may legitimately reshape or recast) or when the spec leaves a dimension symbolic. Unit checks are advisory only.

How it runs#

issues = gm.validate()        # returns a list of strings

Edge issues come back as strings prefixed WARNING[shape], WARNING[dtype], or WARNING[units]. validate() is also run automatically inside gm.compile(), which routes each prefix to a typed warning:

Prefix

Warning class

WARNING[shape]

ShapeMismatchWarning

WARNING[dtype]

DtypeMismatchWarning

WARNING[units]

UnitMismatchWarning

All three subclass EdgeValidationWarning (in maddening/warnings.py), so a caller can warnings.catch_warnings() on the base class to handle them uniformly. In v0.2 these are warnings; the v0.2.1 plan flips shape and dtype to hard EdgeValidationErrors — unit mismatches stay advisory permanently, since units are documentation, not contract.

How MIME stays clean#

MIME’s representative experiment graphs are pinned edge-validation-clean (v0.2 fit-up §4) by tests/verification/test_edge_validation.py. The test builds each experiment graph, calls validate() directly, and asserts no issue carries an edge prefix:

_EDGE_ISSUE_PREFIXES = ("WARNING[shape]", "WARNING[dtype]", "WARNING[units]")
edge_issues = [i for i in gm.validate() if i.startswith(_EDGE_ISSUE_PREFIXES)]
assert not edge_issues

It calls validate() rather than compile() because validate() is the edge check — skipping the JIT keeps the test cheap. LBM/FVM graphs are built at reduced resolution; edge-spec consistency does not depend on lattice size. A new node that introduces a mismatched edge fails here loudly, instead of letting MADDENING v0.2.1 escalate it to a hard error.

Adding a custom node#

To keep validate() clean for a new node:

  • Declare a complete boundary_input_spec() — give every boundary input a concrete shape, dtype, and an expected_units tag where a physical unit applies.

  • Make sure each edge feeding the node produces a field of the matching shape and dtype, or attach a transform that reconciles them.

  • Add the node’s experiment to test_edge_validation.py (register a builder) and confirm gm.validate() reports no edge issue.