Skip to content

EARS criteria

criterion atoms use the Easy Approach to Requirements Syntax (EARS) instead of free-form Given/When/Then prose. EARS is a strict superset of BDD with machine-readable fields.

PatternShapeExample
WHENWHEN <trigger> the <actor> shall <response>WHEN the user taps “Add habit” the system shall open the create form.
IFIF <condition> THEN the <actor> shall <response>IF the habit list is empty THEN the system shall show the empty state.
WHILEWHILE <state> the <actor> shall <response>WHILE the user is offline the system shall queue check-ins locally.
WHEREWHERE <feature toggle> the <actor> shall <response>WHERE the streak feature is enabled the system shall display the streak counter.
UBIQUITOUSthe <actor> shall <response>The system shall persist habit data across sessions.
{
"id": "cri_initial_load_h31a",
"kind": "criterion",
"name": "Initial load shows empty state when no habits",
"pattern": "WHEN",
"actor": "user",
"trigger": "opens the habits screen",
"system_response": "the app shows the empty state message"
}
FieldUsed by patternOptional?
patternallrequired
actorallrequired
system_responseallrequired
triggerWHENrequired for WHEN, otherwise omit
conditionIFrequired for IF
stateWHILErequired for WHILE
feature_toggleWHERErequired for WHERE

The validator enforces the field-per-pattern rule. Hand-authoring a WHEN criterion without a trigger field will fail validation.

A criterion with Layer 2 also carries:

{
"behavior": {
"before_after": {
"state_diff": {
"habits": { "before": [], "after": [{ "id": "h1", "name": "Read" }] }
},
"api_calls": [
{ "method": "POST", "endpoint": "/api/habits",
"body": { "name": "Read" },
"response": { "id": "h1", "name": "Read" } }
]
}
}
}

The state_diff is a per-state-slot before/after pair. The api_calls array is the side-effect log. Pattern C inference between criterion ↔ feature uses these:

  • feature.behavior.stepscriterion.behavior.before_after (forward inference).
  • criterion.behavior.before_afterfeature.behavior.steps (reverse inference).

See Concepts → Four patterns and Codegen → SenLang bridge.

Free-form Given/When/Then prose is unparseable. EARS:

  • Has a fixed grammar — five patterns, three to four required fields.
  • Survives translation — the structure is the same in English, Vietnamese, Japanese.
  • Lowers deterministically into runnable scenarios (RFC-0010).
  • Catches “criterion without a trigger” at validation time.