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.

Python value lab

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.

Current code
score = 85

if score >= 90:
    print("A")
elif score >= 80:
    print("B")
elif score >= 70:
    print("C")
else:
    print("Needs improvement")
Observed result
B
  1. 85 >= 90 → False
  2. 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 diagramStatic if elif else execution path

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% through 24% → emergency charge;
  • 25% through 79% → normal operation;
  • 80% or higher → high charge.

Before writing code, build the edge tests:

BatteryExpected state
9SHUTDOWN
10EMERGENCY CHARGE
24EMERGENCY CHARGE
25NORMAL
79NORMAL
80HIGH 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?andor
FalseFalseFalseFalse
FalseTrueFalseTrue
TrueFalseFalseTrue
TrueTrueTrueTrue

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.

unit04_practice.py

One line is returned for each input() call, in order.

OutputRun with button or Ctrl/Cmd+Enter
Run the code to see output.
Ready to edit. Press Run when you want evidence.

This runs in an isolated Python worker in your browser. Your edits stay in this browser until you reset them.