Canon is a diagram editor that lets users place nodes, connect them with directed edges, and attach geometric constraints—horizontal/vertical alignment and even-spacing. A constraint solver calledDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/metareflection/dafny-replay/llms.txt
Use this file to discover all available pages before exploring further.
Canon reapplies all active constraints in order, producing a deterministic layout. The domain invariant guarantees that all constraints and edges reference only nodes that actually exist, and that constraint IDs remain fresh.
Domain model
The model is defined incanon/Canon.dfy and imported by canon/CanonDomain.dfy. Nodes have string identifiers and integer (x, y) coordinates. Constraints are first-class values with allocated IDs.
CanonDomain module wraps this model with an Action datatype:
Key invariants
m.nodes. This is maintained by filtering out missing nodes when adding constraints (FilterPresent) and by cleaning up constraints and edges when a node is removed (ShrinkConstraints, FilterOutIncidentEdges).
Constraint ID freshness — there is no explicit freshness invariant in Inv (freshness is enforced by the allocator pattern in AddAlign and AddEvenSpace which increment nextCid). The allocator ensures that each new constraint receives a unique ID.
Constraint solver
TheCanon function runs a bounded fixpoint of CanonOnce. Each pass applies all constraints in sequence:
- Align — sets all target nodes’ coordinate along the specified axis to the mean of the group.
- EvenSpace — sorts target nodes by coordinate along the axis and spaces them evenly between the endpoints.
CanonHistory in the AppCore module, which applies Canon to the present state without adding a history entry—so undo skips past the solved layout back to the user-authored one.
RemoveNode cascade
When a node is removed,RemoveNode cleans up all dangling references:
- Constraints that mention the removed node have that node stripped from their target list. Constraints that become degenerate (fewer than 2 targets for
Align, fewer than 3 forEvenSpace) are dropped entirely. - Edges that start or end at the removed node are filtered out.
Inv satisfied without requiring the caller to manually manage referential integrity.
Running the app
Replay kernel
Canon uses the Replay kernel for undo/redo, with
CanonHistory applying the solver outside the history stack.Domain obligations
The two lemmas every domain must prove to plug into a kernel.