# Provenance of flowrs-record Everything in this crate is written for flowRS and licensed MIT OR Apache-2.0, apart from Howard Hinnant's public-domain date algorithms (see `NOTICE`). Per-file origins are listed in `tools/runtime-licence.tsv`. This file records where the record formats' facts come from. ## Re-cited to primary sources (2026-10-27) The licence audit found two files that had read interoperability facts from GPL projects: - `src/stdf.rs` took its field order from pystdf (GPL-2.0); - `src/hardpy.rs` took its key names and enum strings from HardPy's schema module (GPL-3.0). Facts are not copyrightable, but the porting policy wants them cited to a primary source. Each file was compared with the sources below, not with the GPL projects. ### `src/stdf.rs`: the STDF V4 specification | Source | Licence | Checked | |---|---|---| | Teradyne, *Standard Test Data Format (STDF) Specification, Version 4* (FrameMaker edition of 1999-07-06, 103 pages; read from the Internet Archive's copy of `kanwoda.com/wp-content/uploads/2015/05/std-spec.pdf`) | Teradyne documentation; facts only | See below | | *STDF V4-2007 Specification* (from roos.com) | documentation; facts only | The table of record types and sub-types | The following match the specification: - the record header (`REC_LEN` U*2, data bytes only, then `REC_TYP` and `REC_SUB`); - every record's type and sub-type: FAR 0/10, MIR 1/10, MRR 1/20, PCR 1/30, HBR 1/40, SBR 1/50, PIR 5/10, PRR 5/20 and PTR 15/10; - the field order of every record the writer emits and the reader decodes, field by field against the specification's tables; - `CPU_TYPE` 2 (little-endian), `STDF_VER` 4, and the missing-data values (`BURN_TIM` 65535, `X_COORD`/`Y_COORD` −32768, `TEST_T` 0, the space for C*1); - `TEST_FLG` bit 7 (test failed), `PART_FLG` bit 3 (part failed), `HBIN_PF`/`SBIN_PF` `P`/`F`; - the rule that only optional fields at the end of a record may be left off. The writer builds each record with one small encoder per STDF data type, in the specification's field order. It is not a table of field descriptors, which is how pystdf describes records. **Deviation found and fixed (2026-10-27).** The writer used to mark an absent low (or high) test limit with `OPT_FLAG` bit 4 (or 5), and the reader took that bit to mean "absent". It also wrote the reserved bit 1 as 0. The specification's PTR field description says: - bit 1 is "reserved for future used and must be 1"; - bit 4 means "LO_LIMIT and LLM_SCAL are invalid. The default values set for these fields in the first PTR with this test number will be used", and bit 5 the same for the high limit; - "No Low Limit for this test" is bit 6, and "No High Limit" bit 7. The writer now sets bit 1 always, bits 2 and 3 (no LO_SPEC or HI_SPEC is written), and bit 6 or 7 for an absent limit. It never sets bits 4 or 5: each PTR it writes is the first for its test number and carries its own limits. A PTR's `OPT_FLAG` is therefore 0x0E with both limits, 0x8E with only a low limit, 0x4E with only a high limit, and 0xCE with none. The reader follows the specification too. A field after `ALARM_ID` that a PTR leaves out, or that bit 4 or 5 marks invalid, takes the value of the first PTR with the same test number. Bits 6 and 7 mean the test has no such limit. Files flowRS wrote before the fix still read correctly: bit 4 or 5 sat on the first PTR for its test, which has nothing to inherit, so the limit stays absent. The unit tests and `tools/verify_stdf.py` pin the exact bytes and cite the field description. `tools/mutate-stdf.sh` checks that the tests catch each wrong bit. pystdf (GPL-2.0) is only run out of process, as an independent reader of what the writer emits (`tools/verify_stdf.py`). ### `src/hardpy.rs`: HardPy's public documentation, as an interoperability format | Source | Licence | Checked | |---|---|---| | HardPy documentation, *Database* (`everypinio.github.io/hardpy/documentation/database/`, read 2026-10-27) | Documentation of a GPL-3.0 project; names only | Listed below | | HardPy documentation, *pytest-hardpy* API (`everypinio.github.io/hardpy/documentation/pytest_hardpy/`) | as above | Listed below | The *Database* page gives: - the report keys: `_id`, `_rev`, `name`, `status`, `start_time` and `stop_time` (Unix seconds), `dut`, `test_stand`, `process`, `modules`, `user`, `batch_serial_number`, `caused_dut_failure_id`, `error_code` and `artifact`; - the fields of `dut` (`name`, `type`, `serial_number`, `part_number`, `revision`, `sub_units`, `info`), of `test_stand` (`hw_id`, `name`, `revision`, `timezone`, `location`, `number`, `instruments`, `info`) and of `process` (`name`, `number`, `info`); - a module's and a case's keys; - a numeric measurement's keys (`type` `numeric`, `value`, `name`, `unit`, `operation`, `comparison_value`, `lower_limit`, `upper_limit`, `result`); - the statuses `passed`, `failed`, `skipped` and `stopped`. The API page names the comparison operations and gives the role of `lower_limit`, `upper_limit` and `comparison_value`. **Flagged: three names the documentation does not settle.** The module writes them as an earlier reading of HardPy's schema module found them: - operations in lower case (`gtlt`), where the documentation's example shows `"GTLT"`; - the status `error`; - a case's `attempt` key. They should be checked by running HardPy as a black-box oracle: build a report with HardPy's public API, serialise it, and compare. That was not done in this session, because running HardPy here was not approved. ### `src/opentap.rs`: names only `ResultTable` (a name and an array of `ResultColumn`), `ResultColumn` (`Name`, `Data`) and the `Verdict` names (`NotSet`, `Pass`, `Inconclusive`, `Fail`, `Aborted`, `Error`) are cited from OpenTAP's public API reference and documentation (`doc.opentap.io`, 9.35). No OpenTAP code (MPL-2.0) is in this crate.