Concepts¶
The Given-When-Then extension defines two structures: the feature, which is the top-level document, and the scenario, which is a nested entry inside the feature.
Feature¶
A feature is a group of scenarios that share one fachliche Klammer – they are all about the same consistency unit. Picking one consistency unit per feature is the structural rule that keeps scenarios focused: when you find yourself wanting to mix scenarios about an Aggregate and a Process Manager, you have two features, not one.
A feature carries its scope (the unit it is about), an optional description, and a non-empty list of scenarios. The scope's discriminator field – aggregate, dynamicConsistencyBoundary, processManager, or readModel – determines the variant of the feature, and therefore the shape of every scenario inside it.
Aggregate features identify Events by bare name because the feature's scope already fixes the producing Aggregate; DCB, Process-Manager, and Read-Model features carry full Event references because their preceding Events may originate in other Bounded Contexts.
Scenario¶
A scenario is a single behavioral assertion inside a feature. It carries three blocks: given, when, and then.
given lists the preceding Events that put the system into the state the scenario starts from. The list is in append order – earlier entries precede later ones in the Event log. The empty list is legal and means "no preceding history" (initial Commands, Process Manager start, fresh Read Model).
when is the trigger that drives the scenario. The trigger's shape depends on the variant. Aggregate and DCB features take a command plus its data (and an optional actor). Process-manager features take either an incoming Event or the firing of a named timer. Read-model features take a query plus its parameters.
then is the expected outcome. Aggregate and DCB scenarios expect either a list of emitted Events or a rejection. Process-manager scenarios may expect any combination of emits, setTimers, cancelTimers, an instance state, or an ended: true marker. Read-model scenarios expect either the query result or the materialized readModel content.
Cross-Field References Are Modeling Rules¶
when.command pointing at an existing Command, then.rejection.invariant at a named invariant on the unit, when.timer at a declared timer on the Process Manager, when.actor at an Actor permitted by the Command, Event names in given and then.events at known Events – none of these are enforced by the schema itself. They are modeling rules the linter checks separately, in dedicated rules. The rationale is the same as for the core: structural validity is one concern; modeling soundness is another, and keeping them separate makes both easier to evolve.