{
 "about": {
  "method": "batch-stocks@2.0.0",
  "supersedes": "batch-stocks.json (0.10.0), drawn for a pasted five-cell text form before the batch screens; the arithmetic is unchanged (the single-row engine's), the input and the rules are the screens'",
  "recordedOn": "2026-10-21",
  "script": "pipeline/lab-calculators/batch_stocks_2_reference.py",
  "scriptSha256": "bab1e0be471d1af02ee7d93e9755f09d9e353c06062afa969c857500a7282f57",
  "source": "The CSO's rulings on the Batch stocks screens, 21 October 2026 (docs/board/memos/2026-10-21-cso-batch-stocks-screens.md), rulings 1 to 5; the CTO's rulings on the same screens (bst, the 384-row cap)",
  "table": "reagents.9bf9980588.json",
  "tableNames": 75,
  "equation": "make up to V = m × purity / (C × FW), the single-row Molarity engine's own call (volumeForMass)",
  "normalisation": "Unicode NFC; every White_Space character a space, trimmed, runs collapsed; default lower-casing; nothing else",
  "cellReading": "Plain numbers, digits-comma-digits and text only. Thousands groupings (\"1,234.5\"), and point decimals read with Decimal comma on, are the grid's (src/lib/grid/number.ts classifyNumber) and are not covered by this fixture.",
  "examples": "Every value is a stated example of a person's own entry, never a recommended or typical value.",
  "tolerances": {
   "volumes": "the engine's double bit for bit; within 1e-12 relative of the exact rational",
   "statuses, reasons and TSV": "exact"
  }
 },
 "oracle": {
  "name": "Python fractions and decimal",
  "version": "3.13.16"
 },
 "count": 40,
 "recordedOn": "2026-10-21",
 "cases": [
  {
   "name": "tsv-ready-and-refused",
   "about": "The CSO's ruling 5: Tris base from the table (121.136, never PubChem's 121.14), imatinib mesylate typed (11.37 mg at 10 mM, 589.72), and a refused row with its inputs as entered",
   "dc": false,
   "rows": [
    {
     "label": "Tris base",
     "cells": [
      "",
      "60.57",
      "100",
      ""
     ]
    },
    {
     "label": "imatinib mesylate",
     "cells": [
      "589.72",
      "11.37",
      "10",
      ""
     ]
    },
    {
     "label": "Tris",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 121.136,
     "fwText": "121.136",
     "fwSource": "table",
     "mass": 60.57,
     "conc": 100.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 5.000165103685114,
     "volumeExact": "5.000165103685114251750099062"
    },
    {
     "status": "ready",
     "fw": 589.72,
     "fwText": "589.72",
     "fwSource": "typed",
     "mass": 11.37,
     "conc": 10.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 1.9280336430848537,
     "volumeExact": "1.928033643084853828935766126"
    },
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Tris",
      "neighbours": [
       "Tris base",
       "Tris hydrochloride"
      ],
      "more": 0
     },
     "reasonText": "Unclassified: “Tris” is not a name in the reagent table; names match only exactly. The table has Tris base and Tris hydrochloride, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris base\t121.136\ttable\t60.57\t100\t100\t5.000165103685114\tReady\n2\timatinib mesylate\t589.72\ttyped\t11.37\t10\t100\t1.9280336430848537\tReady\n3\tTris\t\t\t50\t100\t\t\tRefused. Unclassified: “Tris” is not a name in the reagent table; names match only exactly. The table has Tris base and Tris hydrochloride, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
  },
  {
   "name": "imatinib-check",
   "about": "The README's check: 11.37 mg at 10 mM, FW 589.72, purity blank: 113700/58972 mL",
   "dc": false,
   "rows": [
    {
     "label": "imatinib mesylate",
     "cells": [
      "589.72",
      "11.37",
      "10",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 589.72,
     "fwText": "589.72",
     "fwSource": "typed",
     "mass": 11.37,
     "conc": 10.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 1.9280336430848537,
     "volumeExact": "1.928033643084853828935766126"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\timatinib mesylate\t589.72\ttyped\t11.37\t10\t100\t1.9280336430848537\tReady"
  },
  {
   "name": "purity-typed",
   "about": "A typed purity of 99 % scales the volume by 0.99",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "99"
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "table",
     "mass": 238.3,
     "conc": 50.0,
     "purity": 99.0,
     "puritySource": "typed",
     "volumeMl": 19.799833824306972,
     "volumeExact": "19.79983382430697182566659113"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t238.302\ttable\t238.3\t50\t99\t19.799833824306972\tReady"
  },
  {
   "name": "purity-blank",
   "about": "A blank purity is 100 %, no correction (the CSO's ruling 1)",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "table",
     "mass": 238.3,
     "conc": 50.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 19.999832145764618,
     "volumeExact": "19.99983214576461800572382943"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t238.302\ttable\t238.3\t50\t100\t19.999832145764618\tReady"
  },
  {
   "name": "purity-100",
   "about": "A purity of 100",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "100"
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "table",
     "mass": 238.3,
     "conc": 50.0,
     "purity": 100.0,
     "puritySource": "typed",
     "volumeMl": 19.999832145764618,
     "volumeExact": "19.99983214576461800572382943"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t238.302\ttable\t238.3\t50\t100\t19.999832145764618\tReady"
  },
  {
   "name": "purity-text-percent",
   "about": "“99%” is text, never 100 %",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "99%"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "text",
      "column": "purity",
      "text": "99%"
     },
     "reasonText": "The purity “99%” is text, not a number; this column is in percent. Type the purity as a number only."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t99%\t\tRefused. The purity “99%” is text, not a number; this column is in percent. Type the purity as a number only."
  },
  {
   "name": "purity-fraction",
   "about": "0.99 would be read as 0.99 %: refused",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "0.99"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "purity-fraction",
      "value": "0.99"
     },
     "reasonText": "A purity of 0.99 would be read as 0.99 percent. If it is a fraction, type the purity in percent; purities at or below 1 percent are not calculated here."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t0.99\t\tRefused. A purity of 0.99 would be read as 0.99 percent. If it is a fraction, type the purity in percent; purities at or below 1 percent are not calculated here."
  },
  {
   "name": "purity-one",
   "about": "A purity of 1: refused",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "1"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "purity-fraction",
      "value": "1"
     },
     "reasonText": "A purity of 1 would be read as 1 percent. If it is a fraction, type the purity in percent; purities at or below 1 percent are not calculated here."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t1\t\tRefused. A purity of 1 would be read as 1 percent. If it is a fraction, type the purity in percent; purities at or below 1 percent are not calculated here."
  },
  {
   "name": "purity-over",
   "about": "A purity of 101: refused",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "101"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "purity-range"
     },
     "reasonText": "Enter a purity above 1 and at most 100 percent."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t101\t\tRefused. Enter a purity above 1 and at most 100 percent."
  },
  {
   "name": "typed-fw-wins",
   "about": "A typed FW always wins over a matching name (source typed)",
   "dc": false,
   "rows": [
    {
     "label": "Tris base",
     "cells": [
      "121.14",
      "60.57",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 121.14,
     "fwText": "121.14",
     "fwSource": "typed",
     "mass": 60.57,
     "conc": 100.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 4.999999999999999,
     "volumeExact": "5"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris base\t121.14\ttyped\t60.57\t100\t100\t4.999999999999999\tReady"
  },
  {
   "name": "match-spaces-case",
   "about": "“ TRIS  BASE ” (a no-break space) matches Tris base",
   "dc": false,
   "rows": [
    {
     "label": " TRIS  BASE ",
     "cells": [
      "",
      "60.57",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 121.136,
     "fwText": "121.136",
     "fwSource": "table",
     "mass": 60.57,
     "conc": 100.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 5.000165103685114,
     "volumeExact": "5.000165103685114251750099062"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\t TRIS  BASE \t121.136\ttable\t60.57\t100\t100\t5.000165103685114\tReady"
  },
  {
   "name": "no-match-tris",
   "about": "“Tris”: two neighbours, named as text only",
   "dc": false,
   "rows": [
    {
     "label": "Tris",
     "cells": [
      "",
      "60.57",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Tris",
      "neighbours": [
       "Tris base",
       "Tris hydrochloride"
      ],
      "more": 0
     },
     "reasonText": "Unclassified: “Tris” is not a name in the reagent table; names match only exactly. The table has Tris base and Tris hydrochloride, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris\t\t\t60.57\t100\t\t\tRefused. Unclassified: “Tris” is not a name in the reagent table; names match only exactly. The table has Tris base and Tris hydrochloride, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
  },
  {
   "name": "no-match-ampicillin",
   "about": "“Ampicillin”: one neighbour",
   "dc": false,
   "rows": [
    {
     "label": "Ampicillin",
     "cells": [
      "",
      "10",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Ampicillin",
      "neighbours": [
       "Ampicillin sodium"
      ],
      "more": 0
     },
     "reasonText": "Unclassified: “Ampicillin” is not a name in the reagent table; names match only exactly. The table has Ampicillin sodium, which has its own formula weight. Enter the formula weight of what you weighed, from its label, or type the table's name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tAmpicillin\t\t\t10\t100\t\t\tRefused. Unclassified: “Ampicillin” is not a name in the reagent table; names match only exactly. The table has Ampicillin sodium, which has its own formula weight. Enter the formula weight of what you weighed, from its label, or type the table's name only if it is what you weighed."
  },
  {
   "name": "no-match-magnesium-chloride",
   "about": "“Magnesium chloride”: its hexahydrate, one neighbour",
   "dc": false,
   "rows": [
    {
     "label": "Magnesium chloride",
     "cells": [
      "",
      "20",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Magnesium chloride",
      "neighbours": [
       "Magnesium chloride hexahydrate"
      ],
      "more": 0
     },
     "reasonText": "Unclassified: “Magnesium chloride” is not a name in the reagent table; names match only exactly. The table has Magnesium chloride hexahydrate, which has its own formula weight. Enter the formula weight of what you weighed, from its label, or type the table's name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tMagnesium chloride\t\t\t20\t100\t\t\tRefused. Unclassified: “Magnesium chloride” is not a name in the reagent table; names match only exactly. The table has Magnesium chloride hexahydrate, which has its own formula weight. Enter the formula weight of what you weighed, from its label, or type the table's name only if it is what you weighed."
  },
  {
   "name": "no-match-tris-hcl",
   "about": "“Tris-HCl” does not match Tris hydrochloride; no neighbour",
   "dc": false,
   "rows": [
    {
     "label": "Tris-HCl",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Tris-HCl",
      "neighbours": [],
      "more": 0
     },
     "reasonText": "Unclassified: “Tris-HCl” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris-HCl\t\t\t50\t100\t\t\tRefused. Unclassified: “Tris-HCl” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "no-match-nacl",
   "about": "“NaCl” does not match Sodium chloride",
   "dc": false,
   "rows": [
    {
     "label": "NaCl",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "NaCl",
      "neighbours": [],
      "more": 0
     },
     "reasonText": "Unclassified: “NaCl” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tNaCl\t\t\t50\t100\t\t\tRefused. Unclassified: “NaCl” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "no-match-copper",
   "about": "“Copper sulfate pentahydrate” does not match Copper(II) sulfate pentahydrate",
   "dc": false,
   "rows": [
    {
     "label": "Copper sulfate pentahydrate",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Copper sulfate pentahydrate",
      "neighbours": [],
      "more": 0
     },
     "reasonText": "Unclassified: “Copper sulfate pentahydrate” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tCopper sulfate pentahydrate\t\t\t50\t100\t\t\tRefused. Unclassified: “Copper sulfate pentahydrate” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "no-match-glucose",
   "about": "“Glucose” does not match D-Glucose",
   "dc": false,
   "rows": [
    {
     "label": "Glucose",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Glucose",
      "neighbours": [],
      "more": 0
     },
     "reasonText": "Unclassified: “Glucose” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tGlucose\t\t\t50\t100\t\t\tRefused. Unclassified: “Glucose” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "no-match-plural",
   "about": "“Tris bases” does not match",
   "dc": false,
   "rows": [
    {
     "label": "Tris bases",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Tris bases",
      "neighbours": [],
      "more": 0
     },
     "reasonText": "Unclassified: “Tris bases” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris bases\t\t\t50\t100\t\t\tRefused. Unclassified: “Tris bases” is not a name in the reagent table. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "excluded-fw-name-matches",
   "about": "An excluded FW on a row whose name matches: left out, never a name match",
   "dc": false,
   "rows": [
    {
     "label": "Tris base",
     "cells": [
      "121.136",
      "60.57",
      "100",
      ""
     ],
     "excluded": [
      "fw"
     ]
    }
   ],
   "expected": [
    {
     "status": "left-out",
     "reason": {
      "code": "excluded"
     },
     "reasonText": "You excluded a cell in this row; it is not calculated."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tTris base\t121.136\t\t60.57\t100\t\t\tLeft out. You excluded a cell in this row; it is not calculated."
  },
  {
   "name": "excluded-purity",
   "about": "An excluded purity: left out, never read as 100 %",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "99"
     ],
     "excluded": [
      "purity"
     ]
    }
   ],
   "expected": [
    {
     "status": "left-out",
     "reason": {
      "code": "excluded"
     },
     "reasonText": "You excluded a cell in this row; it is not calculated."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t99\t\tLeft out. You excluded a cell in this row; it is not calculated."
  },
  {
   "name": "text-mass",
   "about": "“0.5 g” in the mass column: refused, nothing converted",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "0.5 g",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "text",
      "column": "mass",
      "text": "0.5 g"
     },
     "reasonText": "The mass “0.5 g” is text, not a number; this column is in mg. Type the mass in mg, as a number only."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t0.5 g\t50\t\t\tRefused. The mass “0.5 g” is text, not a number; this column is in mg. Type the mass in mg, as a number only."
  },
  {
   "name": "text-fw",
   "about": "Text in the FW column",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "n/a",
      "238.3",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "text",
      "column": "fw",
      "text": "n/a"
     },
     "reasonText": "The formula weight “n/a” is text, not a number; this column is in g/mol. Type the formula weight in g/mol, as a number only."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\tn/a\t\t238.3\t50\t\t\tRefused. The formula weight “n/a” is text, not a number; this column is in g/mol. Type the formula weight in g/mol, as a number only."
  },
  {
   "name": "text-conc",
   "about": "Text in the concentration column",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "~10",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "text",
      "column": "conc",
      "text": "~10"
     },
     "reasonText": "The concentration “~10” is text, not a number; this column is in mM. Type the concentration in mM, as a number only."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t~10\t\t\tRefused. The concentration “~10” is text, not a number; this column is in mM. Type the concentration in mM, as a number only."
  },
  {
   "name": "comma-ambiguous",
   "about": "“2,5” with Decimal comma off: ambiguous",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "2,5",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "comma",
      "column": "mass",
      "text": "2,5"
     },
     "reasonText": "Comma is ambiguous: “2,5” could be a decimal comma or a thousands separator. Use a point, or turn on Decimal comma."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t2,5\t50\t\t\tRefused. Comma is ambiguous: “2,5” could be a decimal comma or a thousands separator. Use a point, or turn on Decimal comma."
  },
  {
   "name": "comma-decimal-on",
   "about": "“2,5” with Decimal comma on: 2.5",
   "dc": true,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "2,5",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "table",
     "mass": 2.5,
     "conc": 50.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 0.20981779422749283,
     "volumeExact": "0.2098177942274928452132168425"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t238.302\ttable\t2.5\t50\t100\t0.20981779422749283\tReady"
  },
  {
   "name": "label-no-mass",
   "about": "A name and nothing else",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "",
      "",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "no-mass"
     },
     "reasonText": "No mass. Enter the mass you weighed, in mg."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t\t\t\t\tRefused. No mass. Enter the mass you weighed, in mg."
  },
  {
   "name": "no-conc",
   "about": "No concentration",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "no-conc"
     },
     "reasonText": "No concentration. Enter the concentration you want, in mM."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t\t\t\tRefused. No concentration. Enter the concentration you want, in mM."
  },
  {
   "name": "no-fw-no-name",
   "about": "No formula weight and no name",
   "dc": false,
   "rows": [
    {
     "label": "",
     "cells": [
      "",
      "100",
      "10",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "no-fw-no-name"
     },
     "reasonText": "No formula weight and no name. Enter the formula weight of what you weighed, from its label."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\t\t\t\t100\t10\t\t\tRefused. No formula weight and no name. Enter the formula weight of what you weighed, from its label."
  },
  {
   "name": "zero-mass",
   "about": "A mass of 0",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "0",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "not-positive",
      "column": "mass"
     },
     "reasonText": "The mass must be a number above 0."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t0\t50\t\t\tRefused. The mass must be a number above 0."
  },
  {
   "name": "negative-conc",
   "about": "A negative concentration",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "-5",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "not-positive",
      "column": "conc"
     },
     "reasonText": "The concentration must be a number above 0."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t-5\t\t\tRefused. The concentration must be a number above 0."
  },
  {
   "name": "zero-fw",
   "about": "A typed FW of 0",
   "dc": false,
   "rows": [
    {
     "label": "anything",
     "cells": [
      "0",
      "10",
      "10",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "not-positive",
      "column": "fw"
     },
     "reasonText": "The formula weight must be a number above 0."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tanything\t0\t\t10\t10\t\t\tRefused. The formula weight must be a number above 0."
  },
  {
   "name": "purity-zero",
   "about": "A purity of 0: above 0 is required (the CSO's P1)",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "0"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "not-positive",
      "column": "purity"
     },
     "reasonText": "The purity must be a number above 0."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t0\t\tRefused. The purity must be a number above 0."
  },
  {
   "name": "purity-negative",
   "about": "A purity of -5 (the CSO's P1)",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      "-5"
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "not-positive",
      "column": "purity"
     },
     "reasonText": "The purity must be a number above 0."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t\t\t238.3\t50\t-5\t\tRefused. The purity must be a number above 0."
  },
  {
   "name": "non-finite-fw",
   "about": "“1e999” in the FW column: the grid reads a number that is not finite as text (the CSO's P2)",
   "dc": false,
   "rows": [
    {
     "label": "anything",
     "cells": [
      "1e999",
      "10",
      "10",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "text",
      "column": "fw",
      "text": "1e999"
     },
     "reasonText": "The formula weight “1e999” is text, not a number; this column is in g/mol. Type the formula weight in g/mol, as a number only."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tanything\t1e999\t\t10\t10\t\t\tRefused. The formula weight “1e999” is text, not a number; this column is in g/mol. Type the formula weight in g/mol, as a number only."
  },
  {
   "name": "no-match-sodium-phosphate",
   "about": "“Sodium phosphate”: exactly three neighbours (the CSO's P3)",
   "dc": false,
   "rows": [
    {
     "label": "Sodium phosphate",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Sodium phosphate",
      "neighbours": [
       "Sodium phosphate monobasic monohydrate",
       "Sodium phosphate dibasic",
       "Sodium phosphate dibasic heptahydrate"
      ],
      "more": 0
     },
     "reasonText": "Unclassified: “Sodium phosphate” is not a name in the reagent table; names match only exactly. The table has Sodium phosphate monobasic monohydrate, Sodium phosphate dibasic and Sodium phosphate dibasic heptahydrate, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tSodium phosphate\t\t\t50\t100\t\t\tRefused. Unclassified: “Sodium phosphate” is not a name in the reagent table; names match only exactly. The table has Sodium phosphate monobasic monohydrate, Sodium phosphate dibasic and Sodium phosphate dibasic heptahydrate, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
  },
  {
   "name": "no-match-sodium",
   "about": "“Sodium”: more than three neighbours, “and {n} more” (the CSO's P3)",
   "dc": false,
   "rows": [
    {
     "label": "Sodium",
     "cells": [
      "",
      "50",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "refused",
     "reason": {
      "code": "unclassified",
      "name": "Sodium",
      "neighbours": [
       "Sodium acetate",
       "Sodium acetate trihydrate",
       "Sodium citrate dihydrate"
      ],
      "more": 8
     },
     "reasonText": "Unclassified: “Sodium” is not a name in the reagent table; names match only exactly. The table has Sodium acetate, Sodium acetate trihydrate, Sodium citrate dihydrate, and 8 more, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tSodium\t\t\t50\t100\t\t\tRefused. Unclassified: “Sodium” is not a name in the reagent table; names match only exactly. The table has Sodium acetate, Sodium acetate trihydrate, Sodium citrate dihydrate, and 8 more, each with its own formula weight. Enter the formula weight of what you weighed, from its label, or type a table name only if it is what you weighed."
  },
  {
   "name": "tab-in-name",
   "about": "A tab inside a name becomes a space in the TSV",
   "dc": false,
   "rows": [
    {
     "label": "HEPES\tlot 7",
     "cells": [
      "238.302",
      "238.3",
      "50",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "typed",
     "mass": 238.3,
     "conc": 50.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 19.999832145764618,
     "volumeExact": "19.99983214576461800572382943"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES lot 7\t238.302\ttyped\t238.3\t50\t100\t19.999832145764618\tReady"
  },
  {
   "name": "skipped-blank-row",
   "about": "A fully blank, unlabelled row between two rows is skipped, and the row numbers keep the grid's",
   "dc": false,
   "rows": [
    {
     "label": "HEPES",
     "cells": [
      "",
      "238.3",
      "50",
      ""
     ]
    },
    {
     "label": "",
     "cells": [
      "",
      "",
      "",
      ""
     ]
    },
    {
     "label": "Tris base",
     "cells": [
      "",
      "60.57",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 238.302,
     "fwText": "238.302",
     "fwSource": "table",
     "mass": 238.3,
     "conc": 50.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 19.999832145764618,
     "volumeExact": "19.99983214576461800572382943"
    },
    {
     "status": "skipped"
    },
    {
     "status": "ready",
     "fw": 121.136,
     "fwText": "121.136",
     "fwSource": "table",
     "mass": 60.57,
     "conc": 100.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 5.000165103685114,
     "volumeExact": "5.000165103685114251750099062"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tHEPES\t238.302\ttable\t238.3\t50\t100\t19.999832145764618\tReady\n3\tTris base\t121.136\ttable\t60.57\t100\t100\t5.000165103685114\tReady"
  },
  {
   "name": "edta-free-acid",
   "about": "“EDTA” matches the free acid under the rule (correct), never the disodium salt",
   "dc": false,
   "rows": [
    {
     "label": "EDTA",
     "cells": [
      "",
      "29.22",
      "100",
      ""
     ]
    }
   ],
   "expected": [
    {
     "status": "ready",
     "fw": 292.244,
     "fwText": "292.244",
     "fwSource": "table",
     "mass": 29.22,
     "conc": 100.0,
     "purity": 100.0,
     "puritySource": "blank",
     "volumeMl": 0.9998494408781703,
     "volumeExact": "0.9998494408781702960539822888"
    }
   ],
   "tsv": "Row\tName\tFW (g/mol)\tFW source\tMass (mg)\tConc. (mM)\tPurity (%)\tMake up to (mL)\tStatus\n1\tEDTA\t292.244\ttable\t29.22\t100\t100\t0.9998494408781703\tReady"
  }
 ]
}
