Systems relate to each other in two structurally different ways, and the overlay keeps them sharply distinct:
composed_of— CONTAINS. A parent system is made of its children. This is the tree the architecture diagram nests on. It must be acyclic.depends_on— USES. A system runs on another (typically infrastructure). This is a cross-stack edge that never nests, and cycles here are only a warning, not an error.
composed_of — the containment tree
Chowk's top-level container gathers the four capability systems into the marketplace as a whole:
system ChowkPlatform {
title "Chowk Platform"
kind capability
owner "chowk-platform-team"
composed_of [
catalog.v1.CatalogSystem,
ordering.v1.OrderingSystem,
fulfillment.v1.FulfillmentSystem,
inventory.v1.InventorySystem
]
doc "The marketplace as a whole — the container every capability system rolls up into."
metadata_type SystemMetadata
metadata {
criticality: "critical"
value_statement: "The marketplace, end to end — browse, buy, fulfil, and the ledger that keeps it honest."
}
feature_type Feature
}That renders as a nested tree in the architecture output:
- Chowk Platform (capability)
- Catalog (capability)
- Fulfillment (capability)
- Inventory (capability)
- Ordering (capability)The children live in other sub-domains, so each is referenced by full .v1 FQN. (A container may cross sub-domain boundaries; a container declared in a leaf sub-domain that nothing imports is what keeps these cross-references from closing an import cycle.)
Container systems carry no numbers
Notice what ChowkPlatform's metadata block leaves out: operating_cost and business_value. That omission is deliberate and is the container convention.
A container's numeric roll-up is the sum of its children, computed for you. If a container also declared its own operating_cost, that number would be double-counted against the children's sum. So a pure container declares metadata_type (still required) but omits the numeric fields — its roll-up is exactly the sum of its leaf children, no more. The string fields (criticality, value_statement) describe the container itself and don't aggregate.
Every numeric metadata field rolls up this way, over the whole containment subtree — so the "metadata roll-ups" table shows each container's totalled cost and value without you adding anything up by hand.
depends_on — the dependency edges
Where composition is containment, dependency is use. Each capability system declares the infrastructure it runs on:
system OrderingSystem {
// …
depends_on [infrastructure.v1.PrimaryDatabase, infrastructure.v1.EventBus]
// …
}OrderingSystem uses the database and the event bus; it is not made of them. These edges never nest into the composition tree — they render as a separate dependency map. Because a dependency crosses the stack (a capability system pointing at an infrastructure system), and typically crosses sub-domain boundaries, each target is a full .v1 FQN.
Composition vs dependency, side by side
composed_of | depends_on | |
|---|---|---|
| Relationship | CONTAINS (is made of) | USES (runs on) |
| Renders as | the nesting tree | dependency edges |
| Typical target | sibling capability systems | infrastructure systems |
| Cycles | a hard error (must be acyclic) | a warning (a smell, not fatal) |
| Numbers | parent sums its children | no roll-up |
Getting the two right is what makes the architecture map honest: the tree shows what the marketplace is composed of, and the dependency edges show what it all runs on — two questions, two edge types, one model.