Composition & roll-ups

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:

sub-domains/platform/_precise/systems.vishwakarma
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:

sub-domains/ordering/_precise/systems.vishwakarma
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_ofdepends_on
RelationshipCONTAINS (is made of)USES (runs on)
Renders asthe nesting treedependency edges
Typical targetsibling capability systemsinfrastructure systems
Cyclesa hard error (must be acyclic)a warning (a smell, not fatal)
Numbersparent sums its childrenno 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.