Checkpoints & Branching

Control OpenHTF test flow with checkpoints that stop on failure and branch sequences that conditionally execute phases based on diagnosis results.

Last updated · Verified with OpenHTF 1.6.1

Stop early on failure or run phases conditionally based on diagnosis results.

A checkpoint phase inspects the outcome of the phases before it. When calibration has failed, the checkpoint stops the test so the long burn-in phase never runs.

  • Test start
  • phase_power
  • phase_calibrate
  • checkpoint("calibration")
  • phase_burn_in10 min
  • Test end

Not every test should run every phase. If calibration fails, there is no point running a 10-minute burn-in. OpenHTF provides two mechanisms for this: checkpoints that stop execution when previous phases fail, and branch sequences that conditionally execute phases based on diagnosis results.

Checkpoints

A checkpoint inspects the outcome of previous phases and decides whether to continue or stop. Place a checkpoint before any expensive phase you want to skip on failure.

main.py
import openhtf as htf
from openhtf.util import checkpoints

@htf.measures(
    htf.Measurement('calibration_offset').in_range(-1, 1)
)
def calibration_phase(test):
    test.measurements.calibration_offset = 5  # Will fail validation

def long_burn_in(test):
    # This should NOT run if calibration failed
    import time
    test.logger.info('Starting 10-minute burn-in')
    time.sleep(600)
    return htf.PhaseResult.CONTINUE

def main():
    test = htf.Test(
        calibration_phase,
        checkpoints.checkpoint('post_calibration'),  # Stops if any previous phase failed
        long_burn_in,
    )
    test.execute(lambda: "SN1234")

if __name__ == "__main__":
    main()

Since calibration_phase fails its measurement, the checkpoint triggers a STOP and long_burn_in never runs.

Checkpoint types

checkpoint(name)str

Stop the test if any previous phase has a FAIL outcome. This is the most common usage.

PhaseFailureCheckpoint.last(name)str

Stop only if the immediately previous phase failed.

PhaseFailureCheckpoint.all_previous(name)str

Stop if any previous phase in the entire test failed. Same as checkpoint().

PhaseFailureCheckpoint.subtest_previous(name)str

Stop if any previous phase within the current subtest failed.

action=PhaseResult

Keyword accepted by all three: PhaseResult.STOP (default) ends the test; PhaseResult.FAIL_SUBTEST fails only the enclosing subtest.

main.py
import openhtf as htf
from openhtf.core.phase_branches import PhaseFailureCheckpoint

def phase_a(test):
    return htf.PhaseResult.FAIL_AND_CONTINUE

def phase_b(test):
    return htf.PhaseResult.CONTINUE

def phase_c(test):
    return htf.PhaseResult.CONTINUE

def main():
    test = htf.Test(
        phase_a,
        phase_b,
        PhaseFailureCheckpoint.last('check_b'),  # Only checks phase_b → PASS, continues
        phase_c,
    )
    test.execute(lambda: "SN1234")

if __name__ == "__main__":
    main()

Stop on first failure

For simpler cases where you want the entire test to stop as soon as any measurement fails, use the stop_on_first_failure test option instead of checkpoints.

main.py
import openhtf as htf

@htf.measures(htf.Measurement('voltage').in_range(0, 5))
def phase_one(test):
    test.measurements.voltage = 10  # Fails

@htf.measures(htf.Measurement('current').in_range(0, 1))
def phase_two(test):
    # This will NOT run
    test.measurements.current = 0.5

def main():
    test = htf.Test(phase_one, phase_two)
    test.configure(stop_on_first_failure=True)
    test.execute(lambda: "SN1234")

if __name__ == "__main__":
    main()

Subtests

Every checkpoint takes an action — PhaseResult.STOP by default. Inside a subtest, pass action=htf.PhaseResult.FAIL_SUBTEST so the checkpoint fails only that subtest and the remaining subtests still run; PhaseFailureCheckpoint.subtest_previous(name, action=...) limits the check to phases of the current subtest.

Branch sequences

Branch sequences execute phases conditionally based on diagnosis results. Combine them with diagnoses to build adaptive test flows.

main.py
import openhtf as htf
from openhtf.core import diagnoses_lib, measurements
from openhtf.core.phase_branches import BranchSequence, DiagnosisCondition

class CalDiag(diagnoses_lib.DiagResultEnum):
    NEEDS_RECAL = 'needs_recal'

@diagnoses_lib.PhaseDiagnoser(CalDiag)
def cal_check(phase_record):
    for m in phase_record.measurements.values():
        if m.outcome == measurements.Outcome.FAIL:
            return diagnoses_lib.Diagnosis(
                CalDiag.NEEDS_RECAL,
                description='Calibration drift detected',
            )
    return None

@htf.diagnose(cal_check)
@htf.measures(htf.Measurement('offset').in_range(-0.5, 0.5))
def check_calibration(test):
    test.measurements.offset = 1.2  # Fails, triggers NEEDS_RECAL

def recalibrate(test):
    test.logger.info('Running recalibration sequence')
    return htf.PhaseResult.CONTINUE

def final_test(test):
    return htf.PhaseResult.CONTINUE

def main():
    test = htf.Test(
        check_calibration,
        BranchSequence(
            DiagnosisCondition.on_any(CalDiag.NEEDS_RECAL),
            recalibrate,  # Only runs if NEEDS_RECAL diagnosed
        ),
        final_test,
    )
    test.execute(lambda: "SN1234")

if __name__ == "__main__":
    main()

Diagnosis checkpoints

DiagnosisCheckpoint(name, condition) stops the test (or fails the subtest) when a diagnosis condition holds — the checkpoint counterpart of a branch:

main.py
from openhtf.core.phase_branches import DiagnosisCheckpoint, DiagnosisCondition

DiagnosisCheckpoint('stop_if_defective', DiagnosisCondition.on_any(TestDiag.BOARD_DEFECTIVE))

Condition types

DiagnosisCondition.on_all(*results)

Execute branch only if ALL specified diagnosis results are present.

DiagnosisCondition.on_any(*results)

Execute branch if ANY of the specified diagnosis results are present.

DiagnosisCondition.on_not_all(*results)

Execute branch if NOT ALL of the specified results are present.

DiagnosisCondition.on_not_any(*results)

Execute branch if NONE of the specified results are present.

On this page

Run it on your stations

$ tofupilot run .
✓ operator UI ready
$ git push
✓ stations updated
✓ runs uploaded

Same OpenHTF script, no code changes.

How it works