Week 04 · lesson

Branches Create Alternate Futures

A branch is where one program becomes several possible programs.

The source file contains all of the paths, but one execution follows only the path selected by the current state. Defensive reasoning gets easier when you stop asking, “What does this code do?” and start asking, “What does this code do under this state?”

One condition can hide several cases

Consider:

role = "operator"
maintenance = False
emergency_stop = False

if emergency_stop:
    action = "stop"
elif role == "operator" and maintenance:
    action = "service-mode"
elif role == "operator":
    action = "run"
else:
    action = "deny"

There are four visible outcomes, but the inputs can combine in many ways.

A branch map helps:

emergency_stop?
├─ yes → stop
└─ no

operator AND maintenance?
├─ yes → service-mode
└─ no

operator?
├─ yes → run
└─ no → deny

The diagram exposes something the source formatting can hide: the emergency condition has priority over every later decision.

Branch coverage is not the same as line coverage

A program can execute every line in separate runs and still have poorly understood combinations.

Suppose you test only:

  • operator + normal mode;
  • operator + maintenance mode; and
  • guest + normal mode.

You have not tested what happens when emergency_stop = True while maintenance is also true. The code suggests the emergency branch wins, but a test is stronger evidence than an assumption.

This is why good testing includes boundary combinations, not just happy paths.

Build a decision table

Use a decision table before editing the program.

rolemaintenanceemergency_stopexpected action
operatorFalseFalserun
operatorTrueFalseservice-mode
guestFalseFalsedeny
operatorTrueTruestop
guestTrueTruestop

The last row looks strange: why would a guest be in maintenance mode? That is exactly why decision tables are useful. They expose combinations the designer may not have considered.

Sometimes the answer is “that state should never exist.” If so, the program should usually enforce that assumption rather than hope it remains true.

Logs turn hidden branches into evidence

A program that returns only deny may be difficult to diagnose. Consider adding bounded diagnostic messages:

if emergency_stop:
    action = "stop"
    reason = "emergency-stop-active"
elif role == "operator" and maintenance:
    action = "service-mode"
    reason = "authorized-maintenance"
elif role == "operator":
    action = "run"
    reason = "normal-operator"
else:
    action = "deny"
    reason = "role-not-authorized"

print(f"action={action} reason={reason}")

Now the output records both the result and the branch explanation.

That is useful, but logging has boundaries too. A reason code should not expose passwords, secrets, private records, or unnecessary personal data.

Useful evidence is specific enough to diagnose behavior and narrow enough to avoid creating a new data problem.

Failure reasoning: the output is wrong, but where?

Imagine this observed output:

action=run reason=normal-operator

The expected state was:

role=operator
maintenance=True
emergency_stop=False

Expected action: service-mode.

Do not immediately rewrite the condition.

Form competing hypotheses:

  1. maintenance was not actually True at runtime.
  2. the value was a string such as "True" rather than boolean True;
  3. another part of the program changed the variable before the branch;
  4. the observed output came from a different version of the program; or
  5. the expected behavior is wrong.

Then ask what evidence would distinguish them.

This is systems troubleshooting: multiple mechanisms can create the same symptom.

Activity: diagnose from a supplied trace

You are given this fictional trace:

08:10:01 input role=operator
08:10:01 input maintenance="false"
08:10:01 input emergency_stop=false
08:10:01 branch emergency_stop -> false
08:10:01 branch operator_and_maintenance -> true
08:10:01 output action=service-mode

The output is suspicious because the text value "false" was treated as truthy by the program that parsed it.

Your job is not to exploit the mistake. Your job is to explain the mechanism.

Record:

  • observation;
  • likely mechanism;
  • evidence supporting it;
  • one alternate explanation;
  • one additional check; and
  • one safe control.

A strong control is not “block hackers.” A strong control is something like:

Parse the configuration field into a strict boolean and reject any value outside the documented representation before evaluating authorization logic.

That statement names a mechanism and a boundary.

Regression tests protect old behavior

Whenever you fix a branch, test both the problem case and behavior that was already correct.

For this week, use three categories:

Positive case

A valid authorized state still works.

Negative case

A prohibited or malformed state is rejected.

Regression case

An unrelated valid state behaves exactly as it did before the change.

A fix that prevents one failure by breaking normal operation is not a strong fix.

Extend your Execution and Input Boundary Record

Add:

Decision table: at least five state combinations.
Observed failure: one supplied branch mismatch.
Primary hypothesis:
Alternate hypothesis:
Evidence needed to distinguish them:
Proposed control:
Regression case that must remain unchanged:

Lesson 3 will turn that proposed control into a tested input boundary.