Method facts: say it in the model
Older models kept these facts in descriptions, comments, or hotspots. Now each fact has a typed block or attribute.
After this page, you can:
- say which block records each method fact
- add a stream identity and a lifecycle to an aggregate
- record evidence, decisions, and hotspots
Method facts are optional. A model without them stays valid. Add them when a team needs the model to say more than the flow shows. The method behind them is in Review a model.
| Fact | Syntax | Core code |
|---|---|---|
| The field that names one stream | aggregate identity | EM018 |
| The states of a stream and the moves between them | lifecycle, state, transition, invalid_transition | EM017 |
| Where the value of a field comes from | field references, field_source | EM202 |
| The fields that link or deduplicate outside facts | correlation_key, deduplication_key | none |
| Where a fact comes from, and how certain it is | evidence_source, evidence | none |
| A choice that shapes the model, and its reason | decision | none |
| The kind of an open question | hotspot kind, category, options, concerns | none |
All of these facts are optional. A model without them stays valid. The v0.8.0 specification defines the rules. The method facts example uses all of them in one booking model. Scenario cases, empty history, and dispatch assertions are on the Scenarios page.
Stream identity
A stream is the history of the Events of one aggregate instance. Use identity when one field type tells one stream from another, for example a booking ID:
Each Event of the aggregate must have a top-level field of the identity field type. A fields entry or a field block with that type counts. A field named booking_id with the type "UUID" does not count. An Event without such a field is EM018.
Lifecycle
Use a lifecycle when a stream moves through business states and some Commands are valid only in some states. It is a top-level block for one aggregate:
aggregate,command, andeventsuse the qualified forms.before = []states that the transition starts the stream.end = truestates that the stream ends in this state.pathis"main","cancel","failure", or"compensation".- An
invalid_transitionstates a Command that is not valid in eachbeforestate. Write thereasonin business words. Each invalid transition is a source for astate_violationscenario.
The validator reports EM017 in these cases:
- a second lifecycle of one aggregate
- a lifecycle without a state
- an empty
eventslist - an empty
beforelist on an invalid transition - one state and Command pair that is both valid and invalid
- a transition Event of another aggregate
A lifecycle adds no flow edge and no scenario. The validator does not compare it with the edges or the scenarios.
Outside its lifecycle, write state.booking.open, transition.booking.cancel_booking, or invalid_transition.booking.cancel_canceled_booking.
Field references and field sources
A field reference names one field of an element: the element reference, then .field., then the field name. Add .field.<name> again for each subfield, for example command.open_booking.field.address.field.city. A field reference names a field definition, not a value. It has no index such as [0].
Use a field_source block in a workflow when a reader must know where the value of a field comes from:
Elements of the same workflow use the local form. Events use the qualified form. The source follows the edges: each input element must connect to the target element by one canonical edge of the workflow. A field of an Event or a Command takes one input. A field of a Read Model, a Screen, or a Processor can take several. Write the rule of a converted or derived value in description. The language stores the rule as text and does not run it.
The validator reports EM202 in these cases:
- an empty
inputslist - an input without a canonical edge to the target
- several inputs for an Event or Command field
- a second source for the same target
The language does not infer a source from equal names.
Correlation and deduplication keys
An outside fact often arrives without your own ID, and it can arrive twice. Use the two key flags on the fields of that fact:
correlation_key = true states that the value links the outside fact to an entity of your system. deduplication_key = true states that a second delivery with the same value records no new fact. Write the flags on field and subfield blocks. On a field_type, they are EM000. The flags add no diagnostic and no scenario rule. To state the duplicate behavior, write a business_duplicate scenario.
Evidence
Use evidence when a reader must know where a rule comes from. An evidence_source names a document, code, an application, or a person. An evidence record states that the source supports one model part:
certainty is "stated" when the source says it clearly, "implied" when it follows from the source, and "assumed" when no source gives it. A "stated" or "implied" record without source is EM000. Several records can attach to one target. Evidence does not change validity or a diagnostic.
Decisions
Use a decision when the team makes a choice that a future reader can question. It holds one statement and one reason. Omit on for a decision about the whole model:
kind is "choice" or "accepted_debt". If you omit it, the kind is "choice". Use accepted debt when the team keeps a shape that a judgment signal reports, and name that code in signal. Only accepted debt can have a signal. On a choice, signal is EM000.
A decision does not change a diagnostic. The model above still reports EM403 with the same severity. A tool can show the decision next to the signal.
Kinds of hotspots
A hotspot can state what kind of open point it is. Use kind = "assumption" when you filled a gap and a person must confirm it. Use kind = "request" when another part of the model must change. If you omit kind, the hotspot is a question.
category is "action", "data", "next", "rule", "example", "view", "who", or "time". options lists the answers that you offer. A request must have concerns, the kind of model part that must change. Another kind must not have it. Both errors are EM000. Only status controls EM406.
What a record can point at
A hotspot, an evidence record, and a decision each name one attach target in on. All three accept a catalog item, a workflow, an owner, an actor, and a workflow-qualified element. The new forms are in this table:
| Target | Example | Records |
|---|---|---|
| Lifecycle part | transition.booking.cancel_booking | hotspot, evidence, decision |
| Field | event.payments.payment_received.field.payment_reference | hotspot, evidence, decision |
| Decision | decision.one_open_bookings_list | hotspot, evidence |
| Hotspot | hotspot.refund_rule | evidence |
A target kind that the record does not accept is EM101. For example, a decision cannot point at a hotspot. A target that is not declared is EM102.
See RFC 0007 for the reasons behind each fact.
Check yourself
An aggregate sets identity = field_type.booking_id. An Event has a field booking_id with the type "UUID". What does the validator say?
Answer
It reports EM018. The field must use the identity field type. A field with the same name and the type "UUID" does not count.
The team keeps a shape that EM403 reports. Where do you write the reason?
Answer
In a decision with kind = "accepted_debt" and signal = "EM403". The decision does not change the severity.
Are the method facts required?
Answer
No. All of them are optional.