A field of a row, as a form edits it: its name, its type as written, what kind of input it takes (text, a number, true or false, a date, one of its values, or else JSON), the values it takes (one of them), and whether it may be left out, or be null.
A page of a table's rows for a viewer: searched (anywhere in the row), filtered (fields equal to values), sorted (by a field, the id or when it was written; newest first by default) and paged in SQLite. Each row's cells (strings as they are, dates as ISO, small things inline, objects as one short line), and the row in full, and as JSON.
Every table with data, and every table the codebase declares: rows, how many are stored as an older row type than the declaring definition's, when one was last written, and that definition.
Write `value` as row `id` of `table` (a new row, with a new id, if there's none), as the table's own writes are: checked against its row type first (the reason, if it doesn't fit), recorded with its schema, and refused when it would share a unique field with another row (that row named). Its id.
JSON (as `toJson` writes it) as a value of schema `s`: strings where it has dates become dates, pairs where it has a map a map, arrays where it has a set a set, digits where it has a bigint a bigint; a union's first member it then fits. What doesn't fit is left as it is, for the check to say so.
A value of schema `s` to start a new row from: each field a value of its type (the first of a union's, preferring one that isn't nothing), optional fields left out.
A row's value as JSON, to read and edit: dates as ISO strings, maps as [key, value] pairs, sets and arrays as arrays, bigints as their digits; `fromJson` brings it back by the table's row type.