# Stage 2 — Conversions

Verdict on this Mac: **PASS**. Linux: **PENDING**.

`Mojoler.Term` is the checked surface. Bad arguments use `enif_make_badarg`. Domain failures are `{:error, reason}` with a fixed atom, created by `enif_make_atom` of a literal. User bytes never become an atom.

| Mode | What happens | Copy of the payload |
| --- | --- | --- |
| `echo_i64` and the other widths | Range is whatever `enif_get_*` accepts. Outside that, `ArgumentError`. | none |
| `add_i64` | `{:ok, sum}` or `{:error, :overflow}` | none |
| `echo_f64` | Integers are not coerced. This OTP raises `ArithmeticError` on `0.0 / 0.0`, so a NaN term was not constructed. The NIF still returns `{:error, :nan}` if `n != n`. | none |
| `echo_atom` | Only `:ok`, `:error`, `:nil`, `true`, `false` | none |
| `copy_binary` | `{:ok, binary, byte_size}`. Empty, NUL, UTF-8, and sub-binaries match Elixir. `<<1::7>>` is `{:error, :not_binary}`. | one new binary |
| `borrow_stable` | Two inspects. `{:ok, size, 1}` when the data pointers match. The pointer is not returned. | none |
| `fill_output` | `enif_make_new_binary`, then the bytes are written in that buffer. | none before the return binary |
| `text_len` | UTF-8 check, no normalization | none |
| `tuple_sum` | Arity 2 | none |
| `list_sum` | Proper lists, length cap 64, depth 1 (a nested list is `:bad_element`) | none |
| `map_n` | Requires integer `n`. Extra keys are dropped. Missing key is `:missing`. | the returned one-key map |

`calloc` descriptors are released with `free`. `enif_alloc` scratch used for tuples is released with `enif_free`. Tests compare against Elixir, not against a second call of the same NIF alone.
