{
  "version": 1,
  "updated": "2026-09-27",
  "about": "Rules the COA Decoder applies to a pasted certificate of analysis. Each field is read with a regular expression (JavaScript and Python compatible, case-insensitive), and each rule turns what was read into a finding. Every rule has a fixture in _ops/coa/fixtures that trips it; check.py:coa_rules_have_fixtures runs them. The decoder interprets documents; it never rates, names or recommends a vendor.",
  "fields": {
    "compound": {
      "pattern": "(?:product|compound|sample|peptide|material|analyte|item)\\s*(?:name)?\\s*[:\\-]\\s*([A-Za-z0-9][A-Za-z0-9+\\-() ]{1,40}?)\\s*(?:\\r?\\n|$|,|;|\\(|\\d+\\s*mg)"
    },
    "purity": {
      "pattern": "(?:purity|hplc(?:\\s*purity)?|assay)[^0-9\\n]{0,24}(\\d{1,3}(?:\\.\\d+)?)\\s*%"
    },
    "measured_mass": {
      "pattern": "(?:observed|measured|found|experimental|detected)\\s*(?:mass|mw|m/z|molecular\\s*weight|\\[m\\+\\d?h\\]\\d?\\+?)?[^0-9\\n]{0,20}(\\d{2,5}(?:\\.\\d+)?)"
    },
    "expected_mass": {
      "pattern": "(?:theoretical|expected|calculated|calc\\.?)\\s*(?:mass|mw|m/z|molecular\\s*weight)?[^0-9\\n]{0,20}(\\d{2,5}(?:\\.\\d+)?)"
    },
    "lot": {
      "pattern": "\\b(?:lot|batch)\\b\\s*(?:no\\.?|number|#|id)?\\s*[:#]?\\s*([A-Za-z0-9][A-Za-z0-9\\-_/]{2,})"
    },
    "date": {
      "pattern": "(?:date|tested|analy[sz]ed|reported|issued)[^0-9A-Za-z\\n]{0,12}(?:on\\s*)?(\\d{4}-\\d{1,2}-\\d{1,2}|\\d{1,2}[/.]\\d{1,2}[/.]\\d{2,4}|(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\\.?\\s+\\d{1,2},?\\s+\\d{4}|\\d{1,2}\\s+(?:jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*\\.?\\s+\\d{4})"
    },
    "chromatogram": {
      "pattern": "(chromatogram|hplc\\s*trace|uv\\s*trace|peak\\s*table|retention\\s*time)"
    },
    "endotoxin": {
      "pattern": "(endotoxin|\\blal\\b|eu\\s*/\\s*mg|eu\\s*/\\s*ml)"
    },
    "accreditation": {
      "pattern": "(iso\\s*/?\\s*(?:iec\\s*)?17025|a2la)"
    }
  },
  "mass": {
    "abs_tolerance_da": 1.0,
    "rel_tolerance": 0.001,
    "proton_da": 1.00728,
    "charges": [
      1,
      2,
      3,
      4,
      5
    ],
    "why": "Mass spectrometry usually reports protonated ions: [M+H]+ is M + 1.007, [M+2H]2+ is (M + 2 x 1.007) / 2, and so on. Average and monoisotopic masses differ by up to about 0.1% for large peptides, so the tolerance is the larger of 1 Da and 0.1% of the expected mass."
  },
  "grades": [
    {
      "min": 99.0,
      "grade": "high",
      "text": "At or above 99%: high for a research peptide, if the method and chromatogram back it up."
    },
    {
      "min": 98.0,
      "grade": "typical",
      "text": "98 to 99%: the level research-grade peptides are commonly sold at."
    },
    {
      "min": 95.0,
      "grade": "lower",
      "text": "95 to 98%: lower; the remaining few percent are other peptides or impurities of unknown identity."
    },
    {
      "min": 0.0,
      "grade": "low",
      "text": "Below 95%: low. More than one part in twenty of the material is something other than the named peptide."
    }
  ],
  "rules": [
    {
      "id": "purity-100",
      "severity": "red",
      "title": "A purity of 100%",
      "explain": "No chromatographic method measures a peptide as exactly 100% pure: there are always small impurity peaks and a measurement uncertainty. A certificate that reports 100% or 100.00% is rounding, templated or not a real measurement.",
      "when": {
        "field": "purity",
        "op": ">=",
        "value": 100.0
      }
    },
    {
      "id": "purity-low",
      "severity": "amber",
      "title": "Purity below 95%",
      "explain": "More than one part in twenty of the material is something other than the named peptide, and a certificate does not tell you what those impurities are.",
      "when": {
        "field": "purity",
        "op": "<",
        "value": 95.0
      }
    },
    {
      "id": "purity-missing",
      "severity": "red",
      "title": "No purity figure",
      "explain": "Without a purity percentage from a stated method, usually HPLC, the certificate does not say how much of the powder is the peptide.",
      "when": {
        "field": "purity",
        "op": "missing"
      }
    },
    {
      "id": "mass-mismatch",
      "severity": "red",
      "title": "The measured mass does not match the peptide",
      "explain": "Mass spectrometry confirms identity. A measured mass that matches neither the expected mass nor any common protonated ion of it means the sample may not be the named peptide.",
      "when": {
        "field": "mass",
        "op": "mismatch"
      }
    },
    {
      "id": "mass-missing",
      "severity": "amber",
      "title": "No mass spectrometry result",
      "explain": "Purity says how clean the sample is, not what it is. Without a measured mass there is no identity check, and a pure sample of the wrong peptide would pass.",
      "when": {
        "field": "measured_mass",
        "op": "missing"
      }
    },
    {
      "id": "mass-confirmed",
      "severity": "good",
      "title": "Identity consistent with the named peptide",
      "explain": "The measured mass matches the expected mass, directly or as a common protonated ion, within tolerance.",
      "when": {
        "field": "mass",
        "op": "match"
      }
    },
    {
      "id": "lot-missing",
      "severity": "red",
      "title": "No lot or batch number",
      "explain": "A certificate has to belong to a specific batch. Without a lot number you cannot tell whether it describes the vial you have, and generic certificates can be reused across batches.",
      "when": {
        "field": "lot",
        "op": "missing"
      }
    },
    {
      "id": "date-missing",
      "severity": "red",
      "title": "No test date",
      "explain": "Peptides degrade. Without a date you cannot tell whether the result is recent or years old, or whether it predates the batch.",
      "when": {
        "field": "date",
        "op": "missing"
      }
    },
    {
      "id": "chromatogram-missing",
      "severity": "red",
      "title": "No chromatogram",
      "explain": "A purity figure without the chromatogram behind it cannot be checked: you cannot see the impurity peaks or how the percentage was integrated.",
      "when": {
        "field": "chromatogram",
        "op": "missing"
      }
    },
    {
      "id": "endotoxin-missing",
      "severity": "amber",
      "title": "No endotoxin result",
      "explain": "Endotoxins are fragments of bacteria that cause fever and inflammation when injected. Purity and mass tests do not detect them; an endotoxin (LAL) result in EU/mg does.",
      "when": {
        "field": "endotoxin",
        "op": "missing"
      }
    },
    {
      "id": "accreditation-stated",
      "severity": "good",
      "title": "The laboratory states ISO/IEC 17025 accreditation",
      "explain": "ISO/IEC 17025 is the international standard for testing laboratories, and bodies such as A2LA accredit against it. Accreditation covers specific methods, so check the lab's scope of accreditation lists the test used.",
      "when": {
        "field": "accreditation",
        "op": "present"
      }
    },
    {
      "id": "accreditation-missing",
      "severity": "info",
      "title": "No laboratory accreditation stated",
      "explain": "The certificate does not mention ISO/IEC 17025 or an accreditation body. That does not make it wrong, but you cannot check the lab's competence from the document.",
      "when": {
        "field": "accreditation",
        "op": "missing"
      }
    }
  ],
  "placeholders": [
    "Example Analytical Laboratory",
    "Sample Supplier"
  ]
}
