Lab Data Field Guide

Reproducible data case study · Version 1.0.0

Reporting fields in 28 ChemVerify sample records

Published · Lab Data Field Guide · AI-assisted analysis

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.

LevelFieldPopulatedJSON null
SampleLabel batch number5 of 2823
SampleLabel quantity in milligrams22 of 286
SampleReceived date13 of 2815
SampleDate sent to the lab13 of 2815
ReportReport URL104 of 1040
ReportReport method label104 of 1040
ResultNumeric value82 of 216134
ResultUnit82 of 216134
ResultResult method label109 of 216107
ResultUncertainty0 of 216216

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 representationCount out of 216
Number with eq68
Number with lt13
Number with gt1
not_detected verdict with null numeric value108
pass verdict with null numeric value22
Null numeric value and null verdict4

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

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

LevelSource fieldDefinition for this analysis
SampleprotocolPublic protocol URL used to identify one sample entry.
Samplelabel_batch_numberBatch identifier recorded from the label, where populated.
Samplelabel_quantity_mgQuantity in milligrams recorded from the label, where populated.
Samplereceived_at, sent_to_lab_atSource calendar date strings for receipt and dispatch to the lab, where populated.
Sampleanalysed_atCalendar date on the sample entry. The earliest of these differs from the earliest nested report date.
Samplevendor_slug, laboratoryRecorded vendor identifier and laboratory name. Used to describe the sample coverage.
Reportreference, report_urlReport reference and link as supplied by ChemVerify. Availability counts presence of a link string.
Reporttested_atCalendar date on the individual report entry.
Report and resultmethodSource method label at its own record level. Report and result labels can differ.
ResultmeasurandExport category string, with null for unclassified rows.
Resultvalue, unitNumeric field and unit as exported. A finite JSON number counts as numeric.
ResultcomparatorRelation code as exported. eq means equal, lt means less than, and gt means greater than when paired with a number.
ResultverdictCategorical result code as exported, such as not_detected or pass. Distinct from the top-level sample verdict.
ResultuncertaintyUncertainty field as exported. All values in this snapshot are JSON null.

field-availability.csv

ColumnMeaning
levelOne of sample, report or result.
fieldA JSON key found at this level.
recordsTotal rows at this level, 28, 104 or 216.
populatedRecords with the key present and a non-null, nonempty value. Zero counts as populated.
json_nullRecords with the key present and a JSON null value.
missing_keyRecords without the key.
empty_string_or_containerRecords with a blank or whitespace-only string, empty array or empty object.
numeric_zeroSubset 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.