# Changelog 0.8

## v0.8.0 — 2026-10-16

### ✨ Added

#### dialects

- `fragment` composes SQL in `where` and in `select` on `find` or `one`. A value is a parameter. `ident` names the field, the same name `where` uses, and a hidden field is refused. The tenant predicate stays (D266).

- `raw` and `explain` run typed SQL from a table handle. The row class names the columns. `"read"` or `"write"` is required. A scoped tenant read keeps the tenant predicate outside the fragment. A raw write on that table is OKM1702 and sends nothing. `explain` returns the plan outside production and sends nothing when `NODE_ENV` is `production` (D268).

- The value `fn()` returns is callable. `slugify(ident("title"))` is a `where` operand. `.as("slug")` names a `select` entry: a numeric return is a number, and any other return is text. `orderBy` does not accept the call. `view(name, (q) => q.from(table))` selects that table. A column list projects those fields. `materializedView()` stays SQL plus declared columns (D271).

#### adapters

- `okmodel/pg/neon` connects with `@neondatabase/serverless`. `websocket` is a pool and `tx()` works on a direct connection. `http` sends one request per statement, and `batch()` is the atomic call. `tx()` on HTTP is OKM1111. A positive timeout is refused. A transaction-mode pooler does not promise session state. With one small compute it reused a backend, so a custom `SET` was still visible on a second connection (D269).

#### runtime

- `insert({ id }, { allow: ["id"] })` writes a supplied id on a client-generator primary key. An omitted id in the same list is still generated. Without `allow`, a supplied id is OKM1190. A database default stays OKM1190 when `allow` names it. On a list, the type opens `id` only when `allow` is exactly `["id"]` (D272).

- `okmodel/otel` turns `hookm`, `onRoute`, and `inspect()` into OpenTelemetry `db.*` spans. You pass the tracer. Statement text stays off unless `statement: true`. Parameters and a tenant id are not recorded. An error span records the error name and an OKM code, and leaves out the message and the stack (D267).

- On a topology client, `inspect().routing.reason` matches `onRoute`. The preview does not call `onRoute` and does not move the selector. A string or a pool stays synchronous `single-endpoint` (D268).

- `connect` from `okmodel/pg/neon` returns a promise for a string, a pool, and a topology. Writes go to the primary. A replica can lag, and `route: "replica"` stays on that replica (D269).

#### tooling

- `okm driver test <driver>` runs the driver, error, and transaction suites and prints each case as pass, fail, or unsupported, with the capability that explains an unsupported case.

- `okm driver test neon` runs those suites. COMMIT loss is unsupported (`no socket to cut`). The Neon connect gate is 42,000 minified and 14,500 gzip (D269).

- A Windows job runs the audit checklist from the packed tarball. It is not a required check. A step that needs a TCP Postgres URL is skipped.

- The repository `.gitattributes` keeps migration SQL, catalog JSON, and `.okm` files LF on checkout (D237).

#### docs

- Offline-first constraints R1–R7 are recorded for the 0.8 train. They do not start a phase. P100 audits PostgreSQL and writes a report (D265).

- The P100 audit records what PostgreSQL already proves for R1–R7, and the gaps later phases still have to decide. No API change.

- The 0.8 type and byte budget is recorded (P101). No gate or ceiling moves. Ali approves it before P102.

- The drivers page covers Neon: WebSocket and HTTP, the pooler, a cold start, and replica lag (D269).

- The P108 study measures four inline-relation shapes. An opt-in entry types `as` and `has` without moving an existing ceiling. The default-path harvest and a loose `references()` store do not fit. No gate moves.

- Inline relations do not ship in 0.8. `relations` on the table remains how an include is named (D270).

- postgres.js and node-postgres results on Neon primary and primary-pool endpoints are recorded. A cause that was not established stays unclassified (D269).

- The OKE Windows audit records 32 surfaces: 27 work, 2 probably work, none fail, and 3 are unknown (#219).

### ♻️ Changed

- The spec status names the 0.8.0 release. Decisions run through D274.

### 🐛 Fixed

- `okmodel/pg/bun` typechecks without `bun-types`. The adapter declarations name the Bun.sql slice they use, so a consumer does not resolve the `bun` module.

- `okm migrate check` and `okm check` reprint a `BEGIN ATOMIC` body before they compare it. An argument qualifier Postgres prints, such as `by_id.n`, is not OKM1547 (D273).

- A raw read renumbers every `$n` marker in a multi-parameter tenant predicate once. Nine user parameters and `$1`, `$2` stay `$10`, `$11`.

- The bundle check leaves `@neondatabase/serverless` external, the same way it leaves `postgres`, `pg`, and PGlite external (D269).

- `okm check` matches a table file stem without case, so `Tasks.ts` with `import { tasks } from "./tasks"` is not OKM1024.

- Packed `okm driver test` finds `dist/tooling/driver-run.js` when the command itself is in a shared chunk. That entry does not import the `bun` package, so Node can run `pglite`. `okm driver test bun` loads the Bun adapter from a chunk of the same build and passes the same pool config as the other drivers.

- The packed bun driver test builds its own runner, so a Postgres consistency shard does not need a prior `dist/` build.
