88. Lesson identity
89. Learning objective
After this lesson, you can write two observable invariants for one mechanic, recognize state and transition forms, and use related postconditions to check whether the mechanic behaves consistently.
90. Why this matters
A mechanic becomes easier to test and revise when its rules state what must always hold. Some rules constrain the game state, while others constrain every applicable action. Writing both forms exposes boundary failures, inconsistent resource costs, and changes that would silently alter the mechanic.
For the Stage 1 milestone, these statements turn a mechanic into behavior that another person can inspect on paper or in play before implementation details become the focus.
91. Prior knowledge
You should have completed 1.3 — Mechanics and rules, Lesson 1: A mechanic is a rule. You should be able to describe a mechanic as an observable rule connecting an action or condition to a response and a change. No programming knowledge is required.
92. Core concept
An invariant is a rule that must hold for every relevant state or transition within a defined scope.
There are two useful forms in this lesson:
- State invariant: a property that must be true in every relevant game state. Example: “The player's health never exceeds maximum health.”
- Transition invariant: a rule that must be true whenever a specified transition occurs. Example: “Every accepted medkit use consumes exactly one medkit.”
A transition invariant does not need to remain visible as an unchanging state property. Instead, it constrains every applicable state change. You check it by comparing the state before and after each relevant action.
A postcondition is a resulting-state requirement attached to an action. For example, a successful medkit use may have the postcondition that health is higher and the medkit count is one lower afterward.
These categories are not always mutually exclusive. A postcondition describes what must be true after an action. If the same requirement is stated as a rule for every valid occurrence of that action, it also functions as a transition invariant. By contrast, recording that one traced use changed the count from 2 to 1 is only an observed outcome of that case; it does not by itself establish a universal rule.
A checkable rule should identify:
- Scope: When does the rule apply?
- Subject: Which state or transition does it constrain?
- Required property: What must be true?
- Observation: What evidence would reveal a violation?
93. Mental model
Use two complementary checks:
| Form | Question | Example | How to check it |
|---|---|---|---|
| State invariant | What must be true in every relevant state? | The medkit count never falls below zero | Inspect the count after normal, repeated, and rejected attempts |
| Transition invariant | What must happen on every applicable action? | Every accepted medkit use consumes exactly one medkit | Compare the count immediately before and after each accepted use |
Use an unambiguous scope:
Whenever the medkit mechanic is active, including when the count is zero.
For postconditions, ask:
What resulting state is required after this action is accepted or rejected?
Then run the mechanic through the Stage 1 loop:
ACT → RESPOND → CHANGE → AGAIN
At each pass, ask:
- Was the action accepted or rejected under the stated conditions?
- Did the resulting state satisfy the action's postconditions?
- Did all relevant state invariants still hold?
- Did the transition obey every universal rule for that kind of action?
AGAIN means repeating the action or inspection, including at a boundary. Repetition helps determine whether a rule applies consistently rather than appearing true in only one trace.
94. Concrete example
Consider this invented mechanic:
When the player uses a medkit while injured and has at least one medkit, the use is accepted: the player restores 20 health without exceeding maximum health and spends one medkit. When the player has zero medkits, the attempt is rejected and the count remains zero.
Checkable rules include:
- State invariant — resource boundary: Whenever the medkit mechanic is active, including when the count is zero, the medkit count is never below zero.
- State invariant — health boundary: The player's health never exceeds maximum health.
- Transition invariant — accepted-use cost: Every accepted medkit use consumes exactly one medkit.
- Transition invariant — rejected-use protection: Every use rejected because the count is zero leaves the medkit count at zero.
A postcondition for an accepted use is:
- After the action, health has increased by up to 20 without exceeding maximum health, and the medkit count is one lower than before.
That postcondition describes the required resulting state. Because the one-medkit cost is required for every accepted use, that part can also be expressed as a transition invariant. An observation such as “this trace began with 2 medkits and ended with 1” is evidence for the rule, but it is not itself the universal rule.
Test the example on paper:
- ACT: Attempt to use a medkit with 40 health and 2 medkits.
- RESPOND: The action is accepted.
- CHANGE: Health becomes 60 and the medkit count becomes 1.
- AGAIN: Repeat with 60 health and 1 medkit, then attempt once more at 0 medkits.
For each accepted transition, compare the medkit count before and after. A change from 2 to 1 or from 1 to 0 satisfies the universal cost rule. A change from 2 to 0 would violate it even though the count remained nonnegative. At zero medkits, accepting the action or producing a count of −1 would violate the specified rules.
This demonstrates why both forms matter: a mechanic can satisfy a state boundary while still violating a transition cost.
95. Common mistakes
Treating invariants as state properties only
“The medkit count never becomes negative” is a state invariant, but it does not verify the exact cost of an accepted use. Add a transition invariant such as “every accepted use consumes exactly one medkit.”
Treating one observed result as a universal rule
“Medkits changed from 2 to 1 in this trace” reports one result. “Every accepted medkit use reduces the count by exactly one” states a rule across all applicable transitions.
Assuming postconditions and transition invariants can never overlap
A postcondition specifies the required result of an action. When that result is required for every valid occurrence, it can also express a transition invariant. Classify statements by their scope and purpose rather than by the word “after.”
Omitting boundary states from the scope
If a rule says the resource count never becomes negative, test an attempted use at zero. Do not use wording that accidentally excludes the zero-resource state.
Writing intentions instead of observable constraints
“The medkit feels useful” is a design intention, not a checkable invariant. Replace it with a state or transition rule that another person can verify.
96. Guided practice
Choose a simple mechanic from the previous lesson or use this one:
A closed door opens when the player has a key. An accepted opening consumes one key. An attempt without a key is rejected.
Create a rule sheet containing:
- One state invariant. State its scope, required state property, and a boundary case that could reveal a violation.
- One transition invariant. State which action it covers, what must happen on every applicable transition, and what before-and-after observation could reveal a violation.
- One postcondition. Describe the resulting state required after an accepted opening. Note any part that also expresses a universal transition rule.
- One boundary decision. Decide what happens when the player attempts to open an already-open door. State whether the attempt is accepted, whether another key is consumed, and which rule protects that decision.
Trace at least two passes of ACT → RESPOND → CHANGE → AGAIN:
- one normal case with a key;
- one boundary case without a key or with an already-open door.
For every trace, record the relevant state before and after the action. Label the observed outcome separately from the universal rule it is meant to check.
97. Validation / evidence
Your evidence is a short rule sheet containing:
- One named mechanic.
- At least one state invariant and one transition invariant.
- A clear scope for each invariant.
- One observable check for each invariant.
- One separately labeled postcondition.
- A note identifying any overlap between the postcondition and a universal transition rule.
- A normal case and a boundary case traced through ACT → RESPOND → CHANGE → AGAIN.
- An explicit decision about repeated or limit behavior.
The work is sufficient when another learner can:
- distinguish a rule about valid states from a rule about valid transitions;
- distinguish a single traced outcome from a universally applicable action rule;
- identify the observation that would prove each rule false;
- apply the rules at the zero-resource or repeated-action boundary.
98. Key takeaways
- State invariants constrain every relevant game state.
- Transition invariants constrain every applicable state change.
- A postcondition specifies the resulting state required after an action.
- A universal postcondition may also function as a transition invariant; the categories are not always exclusive.
- One traced result is evidence, not a universal rule by itself.
- Boundary and repeated-action cases help expose violations that ordinary cases may hide.
99. Next lesson
Bring your completed rule sheet to 1.3 L3 — What a change must not do. Use its state invariants, transition invariants, and postconditions as protected constraints when identifying what an edit must not break.
100. Knowledge check
Answer these items for yourself before reading the answers.
Which statement is a state invariant for a health mechanic?
Show answer and feedback
Answer: The player's health never exceeds maximum health
Why: The maximum-health rule constrains every relevant game state and can be checked at the boundary.
Which statement is a transition invariant?
Show answer and feedback
Answer: Every accepted medkit use consumes exactly one medkit
Why: The statement constrains every accepted use by requiring the same before-and-after resource change.
How can a postcondition relate to a transition invariant?
Show answer and feedback
Answer: A postcondition required after every valid occurrence of an action can also express a transition invariant
Why: A postcondition specifies a required resulting state. When that requirement applies to every valid occurrence, it also constrains the class of transitions universally.
A trace shows that one successful door opening changed the key count from 2 to 1. Which additional statement turns that observed result into a universal action rule?
Show answer and feedback
Answer: Every accepted door opening consumes exactly one key
Why: The trace reports one outcome. The statement about every accepted opening universally constrains all applicable transitions and therefore functions as a transition invariant.