Unit 04 · lesson
Hunt the Boundary
Core path: 30 minutes
Most bad decision logic does not fail in the middle of the obvious cases.
It fails at the edges.
69 versus 70.
79 versus 80.
An empty string versus one character.
A condition that is technically true but appears before the condition that should have higher priority.
This lesson is about finding those edges before a user does.
Thresholds create boundaries
Consider:
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "Needs improvement"
There are three important boundaries:
69 | 70
79 | 80
89 | 90
The useful tests are not random values such as 42, 57, and 93.
Test values immediately on both sides of each boundary:
69 → Needs improvement
70 → C
79 → C
80 → B
89 → B
90 → A
Use the same branch model from Lesson 2 as a boundary-testing instrument. Move the score slowly across each threshold and watch where Python stops checking.
Change the score. Watch Python choose a branch.
Move one input value and watch the first true condition become the only active execution path.
Drag score across the grade boundaries. Predict the output before you move it, then compare your prediction to the execution trace.
Change the values and watch the code, trace, and model update together.
score = 85
if score >= 90:
print("A")
elif score >= 80:
print("B")
elif score >= 70:
print("C")
else:
print("Needs improvement")- 85 >= 90 → False
- 85 >= 80 → True
Current model for score = 85. Active connections show the path or transfer currently being demonstrated.
Drag nodes to inspect the relationships. Motion shows the active path; the plain background keeps attention on the relationships instead of graph-paper decoration.
View static diagram
Why >= is not a cosmetic choice
Change:
score >= 70
to:
score > 70
What happens to exactly 70?
It no longer enters the C branch.
One character changed the policy.
That is why operators are part of the requirement, not punctuation you add after deciding the logic.
Turn requirements into a decision table
Suppose a robot charging station follows these rules:
- below
10%battery → shutdown; 10%through24%→ emergency charge;25%through79%→ normal operation;80%or higher → high charge.
Before writing code, build the edge tests:
| Battery | Expected state |
|---|---|
| 9 | SHUTDOWN |
| 10 | EMERGENCY CHARGE |
| 24 | EMERGENCY CHARGE |
| 25 | NORMAL |
| 79 | NORMAL |
| 80 | HIGH CHARGE |
Now write the branch chain.
If your code cannot pass the table, the table is telling you something useful.
A concrete failure mode: branch order
This looks reasonable at a glance:
if battery >= 25:
state = "NORMAL"
elif battery >= 80:
state = "HIGH CHARGE"
But battery = 90 already satisfies battery >= 25.
Python enters the first branch and stops.
The >= 80 branch is unreachable for every value where it was supposed to matter.
That is a failure mode even though the program has valid Python syntax: the code runs, but the decision policy is wrong.
This is the same reason the ADMIN rule in Lesson 4 had to appear before the broad age rule.
Think of an if/elif/else chain as a set of gates. Once the value passes through one gate, the remaining gates do not get another vote.
and and or change the shape of a rule
Compare:
role == "admin" and code == "A1337"
with:
role == "admin" or code == "A1337"
The first requires both facts.
The second requires either fact.
That difference is massive.
Create this truth table:
| Admin role? | Correct code? | and | or |
|---|---|---|---|
| False | False | False | False |
| False | True | False | True |
| True | False | False | True |
| True | True | True | True |
Now ask which operator actually matches the requirement.
Do not choose and because it sounds stricter or or because it sounds flexible. Translate the policy into logic.
Read a branch chain like evidence
Take your Lesson 4 access-control program and choose the weirdest case you can think of.
Examples:
- blank username + correct admin credentials;
- admin role + wrong code + age 40;
- user role + age exactly 13;
- user role + age exactly 12.
For the chosen case, record:
starting values →
condition 1 result →
condition 2 result →
condition 3 result →
branch selected →
conditions never reached →
That last line matters. In a branch chain, some conditions never execute because an earlier branch already won.
The useful habit
When a requirement contains words like:
at least
more than
less than
no more than
between
only if
unless
slow down.
Those words usually hide a boundary or a compound rule.
The program can be perfectly valid and still be wrong by one value.
That is not dramatic movie-hacker stuff. It is worse: boring, plausible, and easy to ship.
Which is exactly why we test the boundary.
Reader workbench
Probe the decision boundary
This is the Unit's one-file practice surface. Read the code, predict one result, run it, then change a value, input, condition, or boundary and explain why the evidence changed. Multi-file projects, Git, terminals, packages, and live services still belong in the full development workspace.
One line is returned for each input() call, in order.
Run the code to see output.
This runs in an isolated Python worker in your browser. Your edits stay in this browser until you reset them.