The map is generated, not illustrated. A tree-sitter pass parses every file in the package into a graph of symbols and edges, the same way Attestral parses your Terraform and MCP configs into components and edges. Solid lines are module-level imports straight from that index. Dashed lines are imports that happen inside a function, recovered with a source sweep.
The foundation row
One vocabulary, every layer
model.py defines Component, Edge, TrustBoundary, Finding, and Severity. Twenty-one of the other twenty-four modules import it, which is why it sits at the bottom of the map rather than in any one column.
That shape is deliberate. The deterministic rules, the ML scorer, and the LLM judge never talk to each other; they each read the same SystemModel and append the same Finding type. It is the reason findings from three very different analyses land in one severity ordering, one evidence chain, and one SARIF file without translation glue.
The dashed edges
Lazy imports are a design invariant, not a style choice
Most of cli's fan-out is dashed, and that is the point. Anything heavier than click and pyyaml is imported inside the function that needs it: the ML tiers, the LLM layers, the SARIF and AIBOM renderers. A missing optional extra is never an import error, and attestral scan stays fast when you asked for the core scan only.
The scan you run is the diagram you see: ingest builds the model, analysis layers append findings, governance applies waivers, output renders the chain, and the runtime column turns the attested design into policy.