# education.grade-boundaries Turns a raw mark into a grade using a boundary table the caller supplies: each grade starts at its `minMark`, inclusive, and a mark below the lowest boundary is ungraded (`grade` is null). It also says which grade is next and how many marks short the candidate is, which is what a results page or a "marks to the next grade" report shows. ## Why the table is an argument Grade boundaries are not rules in force: they are set per paper, per series, after marking (AQA, Pearson, OCR and WJEC publish a fresh table for every exam series), so there is nothing a registry could carry as dated data that would be right for your paper. Pass the published table for the paper and series you are grading. ## Decisions - **Inclusive lower bounds.** A mark exactly on a boundary earns that grade: boundaries are published as "the minimum mark for grade X". - **Any order.** Tables are usually printed highest grade first; the rows are sorted by `minMark` here, so the order you pass does not matter. - **Ungraded is null, not "U".** Different specifications call it U, X, Fail or "not classified"; label it yourself. A table whose lowest row has `minMark` 0 has no ungraded marks at all. - Integer marks only. A paper marked in halves should be doubled (mark and maxMark and boundaries) before calling. ## Errors A mark outside 0 to `maxMark`, a non-integer mark, an empty table, a boundary outside 0 to `maxMark`, a grade named twice, or two grades sharing one boundary (the table would be ambiguous) all raise.