Test Station Setup

Manage Operator Certification

Track operator training, certification status and test authorization by recording who ran each test and gating on certification.

JJulien Buteau
intermediate9 min readMarch 14, 2026

A new operator runs a test wrong and scraps three boards before anyone notices. It happens more than it should. Most teams track operator certification in spreadsheets that go stale the day they're created.

Tying operator identity to every test run is the part that makes the rest possible: certification gates, yield-by-operator analysis, and an audit trail that survives a regulatory review.

Why Operator Tracking Matters

Regulated industries require it. ISO 13485 (medical devices), AS9100 (aerospace), and IATF 16949 (automotive) all mandate that operators are trained and qualified for the tasks they perform. But even without regulatory pressure, knowing who ran what test matters when you're debugging a yield drop.

Prerequisites

  • A TofuPilot account
  • Python 3.9+ with pip install "tofupilot[openhtf]"
  • An operator authentication method (badge scan, login, or barcode)

Step 1: Record the Operator on Every Run

operated_by is the field that links a run to a person. An email matching a member of your organization links the run to that account; any other value is recorded verbatim as a declared operator name.

operator_tracking.py
22 lines
import openhtf as htffrom tofupilot.openhtf import uploadPROCEDURE_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"  # procedure UUID from the dashboarddef main():    operator_id = input("Scan operator badge: ")    test = htf.Test(        functional_tests,        power_tests,        procedure_id=PROCEDURE_ID,        part_number="PCB-100-R4",        operated_by=operator_id,    )    test.add_output_callbacks(upload())    test.execute(lambda: input("Scan DUT serial: "))if __name__ == "__main__":    main()

Prefer the operator's work email when they have an account, since that links the run to a real member rather than recording a badge string nobody can resolve later.

Step 2: Build an Operator Certification Check

Certification data lives in your own system, not in the test platform. A JSON file works for a small team; an HR API or database is the same shape.

certification_check.py
27 lines
import jsonfrom pathlib import PathCERT_FILE = Path("operator_certs.json")def load_certifications() -> dict:    """Load operator certification records."""    if CERT_FILE.exists():        return json.loads(CERT_FILE.read_text())    return {}def is_certified(operator_id: str, procedure_name: str) -> bool:    """Check if operator is certified for a specific test procedure."""    certs = load_certifications()    operator = certs.get(operator_id, {})    return procedure_name in operator.get("certified_procedures", [])def require_certification(operator_id: str, procedure_name: str) -> None:    """Block test execution if operator isn't certified."""    if not is_certified(operator_id, procedure_name):        raise PermissionError(            f"Operator {operator_id} is not certified for {procedure_name}. "            f"Contact your line supervisor."        )

Example certification file:

operator_certs.json
{  "OP-001": {    "name": "Jane Chen",    "certified_procedures": ["pcba-fct-v2", "motor-fct", "burn-in-48h"],    "certification_date": "2026-01-15",    "expiry_date": "2027-01-15"  },  "OP-002": {    "name": "Mike Torres",    "certified_procedures": ["pcba-fct-v2"],    "certification_date": "2026-02-01",    "expiry_date": "2027-02-01"  }}

Step 3: Gate the Test on Certification

Run the check before the test starts, so an uncertified operator never reaches the first phase.

certified_test.py
26 lines
import openhtf as htffrom tofupilot.openhtf import uploadfrom certification_check import require_certificationPROCEDURE_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"PROCEDURE_NAME = "pcba-fct-v2"def main():    operator_id = input("Scan operator badge: ")    require_certification(operator_id, PROCEDURE_NAME)  # raises if not certified    test = htf.Test(        functional_tests,        power_tests,        procedure_id=PROCEDURE_ID,        part_number="PCB-100-R4",        operated_by=operator_id,    )    test.add_output_callbacks(upload())    test.execute(lambda: input("Scan DUT serial: "))if __name__ == "__main__":    main()

Gating before htf.Test(...) means an uncertified attempt produces no run at all. If you would rather record the attempt, move the check into a first phase and return htf.PhaseResult.STOP instead.

Worth being clear about what this is: a procedural control, not a security boundary. Anyone who can edit the test script can bypass it. It satisfies the audit requirement that a check exists and is recorded; it does not stop a determined person.

Step 4: Track Certification Expiry

Certifications expire. Warn before, block after.

cert_expiry.py
31 lines
from datetime import datefrom certification_check import load_certificationsdef check_certification_status(operator_id: str, procedure_name: str) -> bool:    """Check certification validity with advance warning."""    certs = load_certifications()    operator = certs.get(operator_id)    if not operator:        raise PermissionError(f"Unknown operator: {operator_id}")    if procedure_name not in operator.get("certified_procedures", []):        raise PermissionError(            f"{operator['name']} is not certified for {procedure_name}"        )    expiry = date.fromisoformat(operator["expiry_date"])    today = date.today()    if today > expiry:        raise PermissionError(            f"Certification expired on {expiry}. Recertification required."        )    days_remaining = (expiry - today).days    if days_remaining < 30:        print(f"WARNING: Certification expires in {days_remaining} days")    return True

Step 5: Analyze Operator Performance

With an operator on every run, you can answer questions that matter:

  • Yield by operator: Is one operator consistently lower? They might need retraining.
  • Test duration by operator: Slower operators may be following procedures more carefully, or struggling with the equipment.
  • Failure modes by operator: If one operator sees more of a specific failure, check their technique.

The dashboard groups runs by operator directly. To compute it yourself, query one operator at a time using the operated_by_names filter and count outcomes:

operator_analysis.py
35 lines
import osfrom tofupilot.v2 import TofuPilotPROCEDURE_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"OPERATORS = ["OP-001", "OP-002"]def count_outcomes(client, operator: str) -> dict:    counts = {"pass": 0, "fail": 0}    cursor = None    while True:        result = client.runs.list(            procedure_ids=[PROCEDURE_ID],            operated_by_names=[operator],            limit=100,            cursor=cursor,        )        for run in result.data:            counts["pass" if run.outcome == "PASS" else "fail"] += 1        if not result.meta.has_more:            break        cursor = result.meta.next_cursor    return countswith TofuPilot(api_key=os.getenv("TOFUPILOT_API_KEY")) as client:    for operator in OPERATORS:        stats = count_outcomes(client, operator)        total = stats["pass"] + stats["fail"]        if not total:            print(f"Operator {operator}: no runs")            continue        print(f"Operator {operator}: {stats['pass'] / total * 100:.1f}% ({total} runs)")

Use operated_by_ids instead when your operators are linked organization members rather than declared names.

Two caveats on the number. It counts every run, so a unit that failed and was retested is counted twice; for true first pass yield, take the first run per serial number. And a low figure for one operator is a prompt to look, not a conclusion, since operators rarely test the same mix of products or run the same shifts.

Regulatory Compliance Notes

StandardRequirementHow this maps
ISO 13485Documented training records, competency assessmentOperator on every run, certification check before test
AS9100Personnel qualified for assigned tasksPre-test certification gate
IATF 16949Training effectiveness evaluatedYield-by-operator analysis
FDA 21 CFR 820Personnel training documentedFull audit trail with operator identity

The certification records themselves stay in your system of record. What the test platform contributes is the immutable link from each run back to the person who ran it.

More Guides

Put this guide into practice