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.
The five patterns
Section titled “The five patterns”| Pattern | Shape | Example |
|---|---|---|
WHEN | WHEN <trigger> the <actor> shall <response> | WHEN the user taps “Add habit” the system shall open the create form. |
IF | IF <condition> THEN the <actor> shall <response> | IF the habit list is empty THEN the system shall show the empty state. |
WHILE | WHILE <state> the <actor> shall <response> | WHILE the user is offline the system shall queue check-ins locally. |
WHERE | WHERE <feature toggle> the <actor> shall <response> | WHERE the streak feature is enabled the system shall display the streak counter. |
UBIQUITOUS | the <actor> shall <response> | The system shall persist habit data across sessions. |
Atom shape
Section titled “Atom shape”{ "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"}| Field | Used by pattern | Optional? |
|---|---|---|
pattern | all | required |
actor | all | required |
system_response | all | required |
trigger | WHEN | required for WHEN, otherwise omit |
condition | IF | required for IF |
state | WHILE | required for WHILE |
feature_toggle | WHERE | required for WHERE |
The validator enforces the field-per-pattern rule. Hand-authoring a WHEN criterion without a trigger field will fail validation.
Layer 2 — behavior.before_after
Section titled “Layer 2 — behavior.before_after”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.steps→criterion.behavior.before_after(forward inference).criterion.behavior.before_after→feature.behavior.steps(reverse inference).
See Concepts → Four patterns and Codegen → SenLang bridge.
Why EARS?
Section titled “Why EARS?”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.
See also
Section titled “See also”- Atoms → Content blocks —
criterionfield reference. - Spec → Layer 2 schemas —
before_aftershape. - RFC-002 — Rule expression grammar — for
rule.expression(related but distinct).