# RandomIMEI QA lab — contract 1.0.0

Import a small CSV, inspect every row, and reproduce the browser result offline.
This is an inventory **mock**: no device, MDM, Knox, manufacturer, carrier or GSMA
service is contacted. Names and slots describe a test scenario, not a device
compatibility claim. Synthetic numbers can coincide with assigned identifiers.
Keep fixtures in local/test environments.

## Run the published examples

Requirements: Node.js 20 or later with npm. There are no dependencies and no
installation step. Extract the ZIP, open a terminal inside this directory, then:

```sh
npm test
npm run verify
```

Expected terminal output from `verify`:

```text
PASS mixed: 10 rows; 0 mismatches; mixed.observed.json
PASS apple-mdm: 5 rows; 0 mismatches; apple-mdm.observed.json
PASS samsung-inventory: 5 rows; 0 mismatches; samsung-inventory.observed.json
```

The command writes `*.observed.json` next to the inputs and compares every field
against the included `*.expected.json`. Mismatch or malformed CSV exits with code
1. Published observed reports and `verification.json` record the local reference
run; they are evidence for this fixture, not certification of external systems.

For your own CSV (use `node` directly when redirecting, so npm's banner is absent):

```sh
node cli.mjs inspect my-input.csv > my-report.json
node cli.mjs inspect my-input.csv --csv > my-report.csv
node cli.mjs generate my-seed apple-mdm > generated.csv
node cli.mjs inspect generated.csv > generated-report.json
```

The browser and these commands execute the same `contract.mjs`. The published
seed `randomimei-qa-v1` reproduces the bundled CSVs; the scenario changes fixture
structure, not manufacturer prefixes. The versioned deterministic generator uses
FNV-1a on UTF-16 code units and xorshift32. It is not a cryptographic generator.

## Input and report contract

All identifiers are strings. Never cast them to a number. Import spreadsheet CSV
columns as **Text** before opening: quoting cannot stop a spreadsheet from losing
leading zeros. JSON retains the exact strings; report CSV prefixes a single quote
to formula-like cells to prevent spreadsheet evaluation. That protective prefix
is not part of the original input, which remains available in JSON.

CSV headers: `case_id,record_id,slot,imei,expected_status,expected_duplicate`.
Only `imei` is required. A bare list, one value per line, also works. Unknown or
duplicate headers, duplicate case IDs, inconsistent column counts and malformed
quoting are rejected. A blank line is ignored; use `""` or an explicit CSV row to
test missing input. Maximum 200 cases, 100,000 input characters and 256 characters
per field. Quotes, commas, CRLF, UTF-8 BOM and quoted newlines are supported.

The main generator's full CSV export is also accepted. In addition to `imei`,
its allowed metadata columns are `formatted`, `tac`, `serial`, `check_digit`,
`profile_family`, `profile_label`, `profile_type`, `profile_release_year`,
`mapping_confidence`, `model_identity` and `snapshot_version`. The report inspects
the `imei` string and batch duplicates; it does not validate or infer device
identity from these descriptive fields. Metadata does not become an expected
outcome. The browser's **Export input CSV** retains the original imported CSV,
including these columns; report exports contain only the QA contract fields.

`expected_status` accepts the six values below; `expected_duplicate` accepts
`true`, `false` or an empty field (no assertion). Expectations are compared with
observed values, never copied into the observed result. Machine keys remain
English in every browser language so exports stay portable.

| Status | Meaning |
| --- | --- |
| `valid` | 15 ASCII digits, correct Luhn check digit; no assignment/status claim |
| `body14` | 14 ASCII digits; completion shown separately, original not valid |
| `checksum` | 15 ASCII digits, wrong final check digit |
| `length` | Digits only after normalization, length other than 14 or 15 |
| `characters` | Non-ASCII-digit characters remain after normalization |
| `empty` | Nothing remains after normalization |

Normalization removes JavaScript whitespace, Unicode separators (`\p{Z}`) and
ASCII hyphens only. Unicode digits, en dashes, zero-width spaces and scientific
notation are rejected. The report preserves the original and normalized input.
Luhn doubles positions 2, 4, 6, …, 14 from the left of a 14-digit body.

Duplicates compare **complete 15-digit normalized values** in input order,
including values with a wrong checksum. The first occurrence has `duplicate=false`;
later occurrences reference its case ID. Bodies and malformed values do not
participate. Duplicate is independent of checksum validity. There is no automatic
deduplication, replacement or correction.

`record_id` and `slot` are carried through for inventory inspection. They are not
hardware discovery or a schema-specific Apple/Knox response validator. The Apple
sample demonstrates distinct mock IMEI1/IMEI2, a copied value, a missing second
identifier, and a deliberate checksum error. The Samsung sample demonstrates
normalization before duplicate detection, separate records, a leading-zero edge
case, and a deliberate checksum error. A missing IMEI2 is reported as empty; the
application consuming this data decides whether that slot is required.

Source code is MIT licensed (see LICENSE). Original CSV fixtures and expected
reports are CC0-1.0; no third-party TAC mapping is included.
