AS9100 is the aerospace quality management standard, built on ISO 9001 with additional requirements for configuration management, risk, and traceability. For a test engineer, the practical question is narrower: when an auditor picks a shipped serial number, can you show what was tested, with which equipment, against which revision of the limits, by whom, and when? This guide covers the records AS9100 expects from test, and how to capture them without manual paperwork.
What AS9100 Asks of Test Data
| Clause area | What it means for test | Record you must produce |
|---|---|---|
| Configuration management (8.1.2) | The test that ran matches the released revision | Procedure version recorded on every run |
| Traceability (8.5.2) | Every unit is identifiable through the process | Serial number on every run, linked to sub-assemblies |
| Monitoring equipment (7.1.5) | Instruments were in calibration when used | Instrument ID and calibration due date per run |
| Nonconforming output (8.7) | Failures were detected, segregated, dispositioned | Failed runs retained, with disposition |
| Retention of records (7.5.3) | Records survive and stay readable | Immutable run history, exportable |
| Competence (7.2) | The operator was qualified | Operator identity on the run |
The theme is that a pass/fail verdict is not a record. The record is the measured value, its limits, the revision of those limits, the equipment, the operator and the timestamp.
Step 1: Version the Procedure, Not Just the Code
AS9100 configuration management cares that the test which ran is the released one. Put an explicit version in the procedure and let every run carry it.
procedure.yaml32 lines
name: LRU Acceptance Testversion: 2.3.0description: Acceptance test for the 28V power conditioning LRU, per ATP-4417 rev Cunit: serial_number: default_value: "LRU000001" part_number: default_value: "LRU-4417"plugs: - name: dmm python: plugs.dmm:Multimetermain: - name: Output Voltage python: phases.output_voltage measurements: - name: Output Voltage unit: V description: Per ATP-4417 rev C section 4.2 validators: - operator: ">=" expected_value: 27.5 - operator: "<=" expected_value: 28.5 - name: Ripple unit: mV description: Per ATP-4417 rev C section 4.3 validators: - operator: "<=" expected_value: 150def output_voltage(measurements, dmm): measurements.output_voltage = dmm.measure_dc_voltage() measurements.ripple = dmm.measure_ripple_mv()class Multimeter: def measure_dc_voltage(self) -> float: return 28.02 # Replace with a real instrument read def measure_ripple_mv(self) -> float: return 96.0 # Replace with a real instrument readThe version field is recorded with every run, so results taken before a limit change stay interpretable afterwards. The description on each measurement is where the acceptance test procedure paragraph goes, so the auditor's document and your data line up without a translation step.
Deployments add the other half: the CLI records the exact commit that ran on the station, so "which code produced this result" has an answer that does not depend on anyone's memory.
Step 2: Record the Equipment and Its Calibration
Clause 7.1.5 wants evidence that monitoring equipment was fit for use. Read the identity from the instrument rather than typing it, and record the calibration due date alongside it.
def record_equipment(run, dmm): """Capture instrument identity and calibration status on the run.""" run.metadata["dmm_id"] = dmm.identify() run.metadata["dmm_cal_due"] = dmm.calibration_due()class Multimeter: def identify(self) -> str: return "Keysight 34461A,MY59001234" # Replace with *IDN? query def calibration_due(self) -> str: return "2027-04-18" # Replace with your calibration system lookupMaking the calibration date a measurement rather than metadata turns it into a gate, which is stronger: a station running an out-of-calibration instrument fails the run instead of quietly producing records an auditor will later reject.
- name: Equipment Check python: phases.equipment_check measurements: - name: Calibration Valid description: Instrument calibration in date at time of test validators: - operator: "==" expected_value: truefrom datetime import datedef equipment_check(measurements, dmm): due = date.fromisoformat(dmm.calibration_due()) measurements.calibration_valid = due >= date.today()Step 3: Identify the Operator
Competence (7.2) is about qualified people. The run needs to say who ran it. On a station, prompt for a badge scan as an operator input, and record it.
def record_operator(run, operator_badge): run.metadata["operator_badge"] = operator_badgeFor unattended or CI-driven runs there is no operator, and the honest record says so rather than inventing one.
Step 4: Link Sub-Assemblies
Traceability (8.5.2) rarely stops at the top-level unit. An LRU contains boards, and a board contains a screened component lot. Model the child units so an auditor pulling a shipped serial can walk down, and a containment action can walk up from a suspect lot to every aircraft it reached.
See how to build full unit traceability for the sub-assembly setup.
Step 5: Keep the Failures
A common and expensive mistake is deleting or re-running over failed results to keep a yield number clean. AS9100 clause 8.7 expects nonconforming output to be identified and controlled, which means the failed run is evidence and must survive.
Keep the failing run, record the disposition, and let the retest be its own run under the same serial. The history then shows the failure, the decision and the outcome in order, which is exactly what an auditor is looking for.
Step 6: Run and Retain
tofupilot run ./procedure.yaml --uploadEach run stores the measured values with their limits, the procedure version, the deployment commit, the equipment metadata, the operator, and timestamps. Records are retained and exportable, which covers 7.5.3 without a file server full of spreadsheets nobody can open in five years.
If You Already Run OpenHTF
Existing OpenHTF suites run natively on the TofuPilot CLI with no rewrite, and produce the same records. The equivalent of the version field and the equipment metadata looks like this:
lru_acceptance.py25 lines
import openhtf as htffrom openhtf.util import unitsfrom tofupilot.openhtf import upload@htf.measures( htf.Measurement("output_voltage_V") .in_range(27.5, 28.5) .with_units(units.VOLT) .doc("Per ATP-4417 rev C section 4.2"), htf.Measurement("ripple_mV") .in_range(maximum=150) .with_units(units.MILLIVOLT) .doc("Per ATP-4417 rev C section 4.3"),)def phase_output(test): test.measurements.output_voltage_V = 28.02 test.measurements.ripple_mV = 96.0 test.metadata["procedure_revision"] = "2.3.0" test.metadata["dmm_id"] = "Keysight 34461A,MY59001234"test = htf.Test(phase_output, part_number="LRU-4417")test.add_output_callbacks(upload())test.execute(test_start=lambda: input("Scan serial: "))Install with pip install "tofupilot[openhtf]", or skip the callback and run it with tofupilot run.
Audit Readiness Checklist
| Question an auditor asks | Where the answer lives |
|---|---|
| What was tested on this serial? | The run history for that unit |
| Against which limits? | The measurements stored with the run, including limits |
| Which revision of the test? | The procedure version and the deployment commit |
| With what equipment? | Equipment metadata, or a calibration gate measurement |
| Was the equipment in calibration? | The calibration measurement outcome |
| Who ran it? | Operator metadata on the run |
| What happened to the failures? | Retained failing runs plus the disposition and retest |
| What else used that component lot? | Sub-assembly links from the child serial upward |
Common Mistakes
| Mistake | Consequence | Fix |
|---|---|---|
| Recording pass/fail only | Cannot show margin or drift to an auditor | Store the measured value with its limits |
| Unversioned procedures | Old results become uninterpretable after a limit change | Set version and change it deliberately |
| Typing instrument IDs by hand | Transcription errors in the audit trail | Read *IDN? from the instrument |
| Calibration tracked in a spreadsheet | Out-of-cal equipment produces records you must scrap | Gate the run on a calibration measurement |
| Deleting failed runs | Nonconformance evidence destroyed | Retain the failure, record the disposition |
| No sub-assembly links | Containment means scrapping everything | Model child units from day one |
