Skip to content
UGP v1.0 is a public comment draft. Comments close November 23, 2026. The A–D defect counts are provisional.Public comment draft · until November 23, 2026Comment on this draftComment →
UGPUniversal Grading Protocol
Build

Reference derivation

PDF

How a UGP record becomes a status, a grade, a Premium flag and a core code, as steps an implementation can follow.

The grade, the status and the core code are derived from the record by a deterministic function, and never entered by hand. §4.4 The steward's reference implementation is called computeUgp(record) and returns { status, reasons[], grade, premium, core_code }. This page sets out the same steps in pseudocode, so you can build your own and check it against the golden examples.

1. Battery band

text
if no battery, or sealed            → na
else if charge-hold test            → CP: standard · CF: service
else if no reading, no declaration  → unknown
else if health < 80                 → service
else if health ≥ 90 and measured    → premium
else                                → standard      (80–89 measured, or declared ≥ 80)

§8.2 · §8.4

2. Status: the first rule that matches

text
PROHIBITED   reported lost or stolen; counterfeit; recalled-unsafe; IMEI mismatch or tampering
ENCUMBERED   locks = E or U
UNSANITIZED  data = X or U, and not sealed
PARTS        cosmetic = E;  or functional = FK with disposition: parts
REPAIR       cosmetic = K;  or functional = FM, FJ or FK;  or battery band = service (incl. CF)
NOT GRADED   cosmetic = N;  or functional = FX on an unsealed device;  or battery band = unknown;
             or identity.blacklist.status = unchecked  (reason lost_stolen_unchecked)
READY        none of the above

Collect reasons[] from the lexicon or axis codes that triggered the rule. §11.1

3. Grade

Only a READY record gets a grade, and exactly one:

text
cosmetic S          → NS  New Sealed
cosmetic O          → OB  New Open Box   (kit H → "New Open Box · Handset only")
cosmetic A or A0    → A   Like New
cosmetic B or B0    → B   Very Good
cosmetic C or C0    → C   Good
cosmetic D or D0    → D   Acceptable

The cosmetic value itself comes from the per-zone defect counts and the tolerance table: the best grade whose column every zone fits, with 0 appended when zone AA has no defects at all. §11.2 · §5.5

4. Premium

text
premium = grade = A  and  cosmetic = A0  and  battery band = premium (≥ 90%, measured)  and  parts = G

§10.3

5. Core code

Write every segment in the fixed order, encoding an axis that does not apply as not-applicable, never omitting it:

text
U{major}-{class}-C{cos}-F{func}-B{bat}-L{lock}-R{op}-D{data}-P{parts}-K{kit}[~ext,…]

ext: src:supplier when axes.cosmetic.mapped_from is set

Check the result against the regular expression of §12.2. §12.1 · §12.3

6. Disclosures

Alongside the result, list what every view of the grade discloses: the operator lock if locked, each non-genuine part, the kit if not full, and the battery basis. Two more come from the identity and cosmetic axes: lost_stolen_declared when "not reported lost or stolen" rests on a declaration, and supplier_mapped when the cosmetic value has mapped_from; a supplier-mapped code also ends ~src:supplier. §9.3 · §13.6 §11.4

This page is informative. Where it and the specification differ, the specification governs, and the golden files decide what a correct implementation returns.