Types
The client is typed by the schema passed to connect. Row, Insert, and Update read Register when no schema is passed.
The client is typed by the schema you pass to connect. Row, Insert, and Update use that schema when you pass it, and they read Register when you do not.
The problem
A client typed by a global, and a helper typed by a different global, drift as soon as a project has two schemas. A query result typed by reading the SQL text drifts when the SQL is a string the checker cannot see.
How OKModel handles it
connect requires schema. The client type is that value: one property per table, from ~byName. Register does not replace it. postgres.js, node-postgres, Bun.sql, Neon, and PGlite all require that option.
table() stores ~row, ~insert, and ~update. Those are the shapes the calls use. Row, Insert, and Update take an optional schema type. An explicit schema wins. With the argument omitted, the lookup is Register["schema"]. An empty Register makes that lookup never, and an error's column names stay string until an augmentation names the table.
okm init writes one declare module "okmodel" that sets Register["schema"] to the schema that file exports. A lookup for a different schema passes that schema type.
types is "emitted" when you omit it, and "inferred" when you set that. Both leave the row shapes on the schema value you pass to connect. okm build and okm generate write .okm/types.d.ts from those shapes. The header line is the mode. The flag is not a second set of query types.
What is not inferred
raw(db, sql, params) does not infer the row from the SQL text. The row and the parameters come from .okm/raw.lock.json. A statement that is not in the lock is OKM1601. The other raw call uses the class you pass: each initializer is a result column.
A json or jsonb type argument is erased at runtime. The written interfaces keep it by reading the schema source. That rule is Row types.
Limits and trade-offs
"inferred" is the other stored mode. The written interfaces come from the same shapes either way. What the flag is for, and the file layout, are Row types.
Register holds one schema. A second schema is an explicit type argument on Row, Insert, and Update.
Typed raw SQL is as precise as the lock or the class. It is not a substitute for the table calls. The call is Typed raw SQL.