Declare, don't resolve. A collector knows only the identifier of what an asset talks to
(a role ARN, a queue URL, an image URI, a subnet ID). It records that identifier as a relation
on the asset. Resolution into an edge happens once, in the linker, over the whole inventory,
so a function in account A that reads a queue in account B in another region links correctly
no matter which collector ran first.
No scanner, no writes. Mapping runs only read-only Describe* / List* / Get* calls
(plus the Kubernetes API GETs and the Resource Graph / Cloud Asset Inventory queries). It
never runs a security scanner; findings can be overlaid later.
Breadth with precedence. Deep collectors produce detailed assets; breadth sweeps (AWS
Cloud Control and Tagging API, Azure ARM sweep, GCP Cloud Asset Inventory) make sure nothing
is missing; deduplication keeps the richest copy.
Absence is data. A security service that is not enabled becomes a placeholder asset with
enabled: false; a reference to an unmapped account becomes an external account node; a
reference to nothing is listed as unresolved. Gaps show on the map instead of disappearing.
No secret ever enters the inventory. Values that could be secret are dropped at
collection time, not filtered at export time.
One model for three clouds. AWS, Azure and GCP produce the same CloudAsset /
NetworkEdge model, the same relation objects, and go through the same linker.