Reproducible data case study · Version 1.0.0
Reporting fields in 28 ChemVerify sample records
A frozen ChemVerify export contains 28 sample records, 104 lab report records and 216 result rows. Numbers and units appear together in 82 result rows. Another 108 rows carry the categorical verdict not_detected, 22 carry pass, and four have neither a numeric value nor a verdict. This case study measures which fields the public export contains. ChemVerify dataset · Public JSON export
Lab Data Field Guide is a ChemVerify-associated educational publication. ChemVerify published the export and says it commissioned the laboratory testing. This analysis has not received an independent expert review.
Count samples, reports and results separately
ChemVerify purchased the samples and commissioned testing. The snapshot covers a nonrandom collection associated with ChemVerify. It contains records for five vendors, with 20 of 28 samples from one vendor, and lists one laboratory, Janoshik Analytical. The analysis includes every record in the snapshot. It counts each top-level sample once, each nested report once and each nested result once. Sample protocol URLs and report references are unique in this file. A report can have several result rows, so 216 rows represent 216 entries at the result level. ChemVerify dataset and collection description
The sample field analysed_at runs from September 2 to November 11, 2026. The report field tested_at runs from August 28 to November 11, 2026, matching the date range declared at the top of the export. In 65 report records, the test date differs from the parent sample's analysis date. Use the field that corresponds to the event you are counting. Public JSON export
Which fields were populated?
A field was counted as populated when its key held a non-null, nonempty value. Explicit numeric zero would count as populated. Every observed key existed on every record at its own level in this snapshot. Unpopulated entries in the table were all JSON null.
| Level | Field | Populated | JSON null |
|---|---|---|---|
| Sample | Label batch number | 5 of 28 | 23 |
| Sample | Label quantity in milligrams | 22 of 28 | 6 |
| Sample | Received date | 13 of 28 | 15 |
| Sample | Date sent to the lab | 13 of 28 | 15 |
| Report | Report URL | 104 of 104 | 0 |
| Report | Report method label | 104 of 104 | 0 |
| Result | Numeric value | 82 of 216 | 134 |
| Result | Unit | 82 of 216 | 134 |
| Result | Result method label | 109 of 216 | 107 |
| Result | Uncertainty | 0 of 216 | 216 |
The report and result method labels answer different coverage questions. All 104 reports had a method label. Only 109 result rows had one, and nine of those labels differed from the corresponding report label. Keep the fields separate if you need to trace how the export describes each measurement. A null uncertainty field records what the export provides. It gives no basis for assigning zero uncertainty or determining what appears in the underlying report.
Keep numbers, bounds and verdicts distinct
| Result representation | Count out of 216 |
|---|---|
Number with eq | 68 |
Number with lt | 13 |
Number with gt | 1 |
not_detected verdict with null numeric value | 108 |
pass verdict with null numeric value | 22 |
| Null numeric value and null verdict | 4 |
All 82 numeric rows have a unit and none contains explicit zero. They comprise 31 content rows in mg, 26 endotoxin rows in EU/Vial and 25 purity rows in %; these are the original unit strings, without inferred denominators. All 14 inequality values belong to endotoxin entries. A number with lt or gt preserves a bound, so an analysis of measured magnitudes needs to keep those qualifiers. The 108 not_detected rows are heavy-metal entries, four per report across 27 reports. Each of these rows has null numeric value and unit. Encoding their values as zero would introduce 108 zeroes absent from the export. The 22 pass rows are LC–MS entries without a numeric value. The four rows without a number or verdict are labeled Endotoxin, Benzyl Alcohol, pH and Comment. These are entries in nested results arrays, not necessarily 216 analytical measurements. The comparator is present on all 216 rows, including 134 rows without a number, so a comparator by itself does not identify a numeric observation.
Reproduce the field counts
Download the frozen JSON snapshot and the Python analysis. Run python3 analyze.py alongside the snapshot metadata to regenerate the three aggregate CSV files and the summary. The field counts describe this public export and cannot establish the completeness of the original lab reports. The collection supports descriptive examples of reporting structure. Its sampling and single-laboratory coverage limit comparisons and generalization.
Source credit goes to ChemVerify (2026), Independent peptide lab tests [data set], licensed under CC BY 4.0. Lab Data Field Guide counted and grouped fields without changing or imputing source values. The unchanged bytes were verified by HTTPS retrieval at 2026-11-12 11:24:41 UTC. SHA-256 451bee625402c1f15b7cf29ea6cbdf46d7bd915631aec9aef0753bca6c470ad8. ChemVerify dataset · CC BY 4.0
Download and reproduce
Download the complete study package (ZIP)
Requires Python 3.9 or later; no third-party packages. The optional independent verifier also requires SQLite with JSON functions enabled. Extract the package, then run these commands in its folder:
python3 analyze.py
python3 verify.py- source-snapshot.json
- snapshot-metadata.json
- summary.json
- field-availability.csv
- result-status.csv
- measurand-coverage.csv
- analyze.py
- verify.py
- data-dictionary.md
- LICENSE.txt
- case-study.md
Data dictionary
Source and units of observation
The input is an unchanged JSON snapshot of ChemVerify's public export. Each element in samples is a sample record. Each element in a sample's reports array is a report record. Each element in a report's results array is a result row. Protocol URLs identify sample records in this snapshot. Report references and report URLs each identify report records. Result rows use their nested position and have no explicit identifier in the source. ChemVerify dataset · JSON export
The analysis includes all records and changes no raw data. It measures data availability in the export and makes no assessment of fields on the linked original reports. The file snapshot-metadata.json identifies the byte-for-byte source snapshot.
Source fields used in the article
| Level | Source field | Definition for this analysis |
|---|---|---|
| Sample | protocol | Public protocol URL used to identify one sample entry. |
| Sample | label_batch_number | Batch identifier recorded from the label, where populated. |
| Sample | label_quantity_mg | Quantity in milligrams recorded from the label, where populated. |
| Sample | received_at, sent_to_lab_at | Source calendar date strings for receipt and dispatch to the lab, where populated. |
| Sample | analysed_at | Calendar date on the sample entry. The earliest of these differs from the earliest nested report date. |
| Sample | vendor_slug, laboratory | Recorded vendor identifier and laboratory name. Used to describe the sample coverage. |
| Report | reference, report_url | Report reference and link as supplied by ChemVerify. Availability counts presence of a link string. |
| Report | tested_at | Calendar date on the individual report entry. |
| Report and result | method | Source method label at its own record level. Report and result labels can differ. |
| Result | measurand | Export category string, with null for unclassified rows. |
| Result | value, unit | Numeric field and unit as exported. A finite JSON number counts as numeric. |
| Result | comparator | Relation code as exported. eq means equal, lt means less than, and gt means greater than when paired with a number. |
| Result | verdict | Categorical result code as exported, such as not_detected or pass. Distinct from the top-level sample verdict. |
| Result | uncertainty | Uncertainty field as exported. All values in this snapshot are JSON null. |
field-availability.csv
| Column | Meaning |
|---|---|
level | One of sample, report or result. |
field | A JSON key found at this level. |
records | Total rows at this level, 28, 104 or 216. |
populated | Records with the key present and a non-null, nonempty value. Zero counts as populated. |
json_null | Records with the key present and a JSON null value. |
missing_key | Records without the key. |
empty_string_or_container | Records with a blank or whitespace-only string, empty array or empty object. |
numeric_zero | Subset of populated records whose value is the number zero. |
The four availability categories populated, json_null, missing_key and empty_string_or_container sum to the denominator per field. numeric_zero is a subset.
result-status.csv
status is a mutually exclusive result classification. records is the number of result rows in that class. denominator is all 216 result rows. A finite numeric value takes precedence in classification. A nonnumeric row is grouped by its verdict. The numeric equality and inequality codes retain the original comparator. No result values are converted to zero.
measurand-coverage.csv
measurand uses the original category string or the display value JSON null. samples_with_category and reports_with_category count distinct parents with at least one result in that category. These parent counts can overlap across category rows. results counts result rows in the category. numeric_value, json_null_value, unit_populated, uncertainty_populated and the status columns are counts within that category.
summary.json
The summary records source identity, retrieval time and hash, cohort sizes and date ranges, the number of reports per sample, the number of results per report, numeric-result coverage, comparator counts and the rows from each CSV. Values are counts unless the field names specify a date, URL, status or Boolean.
Cite this analysis
Lab Data Field Guide (2026). Reporting fields in 28 ChemVerify sample records. Version 1.0.0. Published by ChemVerify. https://labdatafieldguide.com/resources/reporting-fields-2026-11-12/
The original analysis text, code and derived counts are released under CC BY 4.0. The unchanged source dataset retains its separate ChemVerify attribution. Linked laboratory reports are not republished in this package.
Explore the guide to detection and quantitation limits and guide to reporting uncertainty.