Resource and module expansion
Resources and modules accept either for_each or count at the declaration level, outside meta. They are mutually exclusive. Expansion occurs during compilation and produces ordinary resources and module instances in the bundle.
Named instances
for_each accepts a map or a set of strings. Map keys or set values establish identity; each.key and each.value belong to that instance. Keys must be nonempty strings without control characters. Lists are not implicit sets: use toset(["first", "second"]) when appropriate.
Sensitive identities fail without entering addresses or diagnostics. Public map keys may accompany sensitive values. Marking an entire variable sensitive taints its keys too, so it cannot provide public expansion identity.
Numbered slots
count requires a public, nonnegative compile-time integer, including an integer fact, and exposes count.index. Named keys render with quotes (file.messages["first"]); numeric slots render without them (file.slots[0]). String and numeric keys are distinct serialized identities. Indexed references must use the corresponding key type.
Zero count and empty collections create no instances. Compilation permits at most 10000 resources and 1024 module instances; each expansion is bounded and nested modules share the global limits.
Module families
Use the file module from modules:
Whole expanded module families can be used in ordering metadata; Rivet expands them to instance boundaries. Individual outputs use an indexed module instance.
Identity changes and removal
Reordering named keys preserves addresses and catalog digests. Reordering a list selected by count can assign an existing slot to a different physical object. Changing a key creates a new declaration.
Removing a key or reducing count does not delete host objects or undo earlier side effects. Obsolete journal work is superseded on the next real apply; declare explicit absent resources when host-object removal is intended. See recovery.