# Changelog 0.18

## v0.18.5 — 2026-08-28

### ♻️ Changed

#### Docs

- Formalized the Canonical Site Knowledge Model (`concept-graph.ts`) defining the 8 closed core primitives, their irreducible physics, and architectural composition formulas.

- Restructured documentation information architecture into 5 numbered stages (`01 Understand`, `02 Build`, `03 Operate`, `04 Extend`, `05 Reference`) across `meta.json` and the handbook index.

- Refactored Elements and AI handbook overviews to emphasize the closed primitive set, inbound MCP vs outbound AI runtime separation, and composition patterns (Realtime, Security, Agents, Operations).

- Standardized site positioning statements and identity constants (`SITE_CATEGORY`, `SITE_PHILOSOPHY`, `SITE_INSPECTABILITY`, `SITE_TAXONOMY_EQUATION`, `SITE_MANIFEST_DISTINCTION`) in `site-identity.ts`.

## v0.18.4 — 2026-08-28

### ♻️ Changed

#### Docs

- Reorganized documentation information architecture into Layer 1 (Understand OKE) and Layer 2 (Build with OKE) per the positioning map.

- Updated landing page hero and narrative arc to the 10-step argument with dedicated architectural proof stories (Realtime, Security, Agents, Observability).

- Refined positioning vocabulary across package metadata, introduction, and why thesis: retired "10 exports" / "entire public vocabulary" in favor of "core programming vocabulary", and clarified MCP client vs Gate provider roles.

## v0.18.3 — 2026-08-28

### 🐛 Fixed

#### Runtime

- Manual live-query HTTP e2e types use a minimal SSE reader shape so `tsc` no longer fails on missing `ReadableStreamReadResult` / `readMany`.

## v0.18.2 — 2026-08-28

### 🐛 Fixed

#### Runtime

- Realtime bridge rebinds when boot hands a new primary SQL connection (fresh PGLite per test) instead of classifying CDC against a prior instance; `createTestApp().close()` calls `app.stop()` so the process-wide sink tears down with the harness.

## v0.18.1 — 2026-08-28

### 🐛 Fixed

#### Runtime

- Manual live-query HTTP e2e no longer waits for two SSE chunks after a single tasks insert (one classified upsert is enough) and raises the Bun test timeout so PGLite boot + CDC fan-out fit under CI load.

## v0.18.0 — 2026-08-28

### ✨ Added

#### Runtime

- Manual live queries — hand-written flows declare live query surfaces with `http.get("/tasks/live").gate(member).live(tasks)` plus `liveQuery(fx, tasks, input, { filter, search, order })` in the flow body. Compiles to the same internal `oke/live/sql:<table>` signal, guardrails, and per-subscriber classified CDC stream as `store.resource({ live: true })`; the PostgREST list grammar is extracted into a standalone shared module (`parseListQuery` / `resolveListScope`) so resource lists, live windows, and hand-written flows parse identically.

- Realtime live queries — `store.resource({ live: true })` synthesizes `GET <path>/live` SSE with per-subscriber RLS classification (`upsert` / `revoked` / `delete`). Application-level CDC via the sql-session write hook + `oke_cdc_outbox` SKIP LOCKED poller; fan-out through `LiveQueryRuntime` (bounded worker pool). `oke.row_passes_policies` parity-gated against native Postgres RLS.

- `useLiveQuery` (`okengine/client-react`) — snapshot + SSE race protocol, three-event reducer, optimistic `mutate()` wrapping existing `ClientCall` envelopes. Pure helpers (`reduceLiveQueryRows`, `applyOptimisticPatch`) also on `okengine/client`.

- `store.schema.policy.scope(PolicyGateDecl | string)` — DRY gate refs in RLS policies.

- G16 live-query fan-out bench (`src/bench/g16-live-query-fanout.bench.ts`).

- CDC outbox retention defaults (24h max-age / 50k-row count cap, configurable via `retention`) — the durable event table now prunes itself like every other Signal/Journal surface.

- `X-Oke-Mutation-Id` end-to-end: mutation requests carry a client UUID header; writes echo it onto their CDC events (in-process and outbox-round-tripped) so `useLiveQuery` dedupes its own late echoes — the realtime optimistic-race contract.

- `useLiveQuery` gains `enabled: false` idle mode, manual `refetch()`, `isReconnecting` (distinct from first-load `isLoading`), reconnect seq-guard replay dedup (`isReplayedEvent`), and identity refresh via `onAuthRefresh` (full subscribe-protocol re-run on auth change).

- Compiler guardrails for `store.resource({ live: true })` — missing primary key fails extract loud; missing `updatedAt`/`updated_at` column and missing RLS policies warn with remediation intent.

- Realtime operations surface: `realtimeMetrics()` snapshot (subscribers, fan-out queue depth, shed/check counters, outbox backlog gauges) plus four new `oke doctor` findings — `cdc_outbox_backlog` (warn >10k / error >100k), `cdc_outbox_retention`, `live_subscriber_pressure` (>150 subs), and `live_fanout_queue_saturated`.

- Project-wide live-by-default: `oke({ store: { live: true } })` flips the default posture for NEW `store.schema.table()` declarations to live — the automatic CDC + RLS-per-event stream `store.resource({ live: true })` already provides — unless a table opts out with `store.schema.live(false)` (or `store.resource(…, { live: false })`). Declaration ergonomics only; the runtime/fan-out cost model is identical to explicit `live: true` (per-subscriber stamped RLS checks, documented in store docs). Flag defaults `false` — existing explicit-only behavior unchanged, zero cost when off. Same DX Pack A guardrails fire on the default-flip path.

- `field.*` widens from `text | integer` to the full Drizzle Postgres column surface — `varchar` / `char` (with `length` + enum literals), `boolean`, `smallint`, `bigint`, the serial family, `numeric` / `decimal` (`precision`/`scale`/`mode`), `real` / `doublePrecision`, `json` / `jsonb` (generic payload), `uuid`, `time` / `timestamp` / `date` / `interval`, `point` / `line`, `bytea`, and the network family (`inet` / `cidr` / `macaddr` / `macaddr8`). Options bags carry per-type knobs; temporals infer `Date` by default with `{ mode: "string" }` opting into ISO strings; the serial family is NOT NULL by SQL physics.

- `.type<T>()` builder override (mirrors Drizzle `$type<T>`) and typed `.default(value)` that rejects values outside the column's JS type.

- Prepared default shorthands — `.okid()` (fresh OKID on insert) and `.now()` sugar over `defaultFn(id)` / the `now` family; `.now()` resolves by the column — epoch-ms on numbers, `Date` on default/date-mode temporals, ISO-8601 on string-mode temporals.

- Drizzle emitter emits drizzle-exact factory calls per type (options, pinned temporal modes) and collects the `drizzle-orm/pg-core` import list dynamically.

- Manifest columns record the widened types plus `enumValues`, `length`, `precision`, `scale`, `withTimezone`, `mode`, and `fields`.

- `okengine/okid` — native id generator `okid()` (21 chars, 126 bits, URL-safe `a-zA-Z0-9-_`), opt-in `{ sortable: true }` time prefix and alphabet control (`numbers` / `lowercase` / `uppercase` / `symbols` / `lookAlikes`). Zero dependencies, `crypto.getRandomValues()` only, rejection-sampled for bias-free character selection.

- `oauth()` plugin — Authorization Code + PKCE social sign-in for Apple, Discord, Facebook, Figma, GitHub, Google, Microsoft, and X. Hand-rolled drivers (OIDC JWKS verify or OAuth2 profile fetch), Vault-declared client secrets, optional sealed provider-token storage, and identity only through `linkOrProvision`.

#### Dev, Keel & create-oke

- Keel inbox mounts `GET /inbox/live` (live query stack); `bindCrud({ live: true })` wires the same surface for any CRUD unit.

- `oke doctor` `file_descriptor_limit` check — estimates peak FDs from the manifest (live signals + SSE routes) and compares against `ulimit -n`.

- `bun run bench:load` + `src/bench/` — system load harness (15 groups) for regression trend runs against live Keel infra (`OKE_BENCH=1`).

#### Docs

- Store + Client docs cover `live: true` and `useLiveQuery`.

- Plugins → **OAuth** category: overview plus per-provider pages (Apple, Discord, Facebook, Figma, GitHub, Google, Microsoft, X).

#### Test harness

- Public `okengine/testing` subpath (aliased `okengine/test`) exposing `createTestApp` — a dedicated `dist/testing.js` build keeps the harness out of core/client production bundles (kernel + client budget gates cover it).

- Multi-tenancy testing: `loginAs({ tenantId })` stamps `fx.tenant.id`, and `{ tenant }` on API calls re-scopes a single call — verified with real PGlite RLS isolation (`store.schema.policy.tenant`).

- Deterministic live signals: `signals.subscribeLive` / `signals.waitForLive` give test-first assertions over `delivery: "live"` event streams (`retention`-aware replay).

- Testing guide at `get-started/testing.mdx` — harness surface, multi-tenant RLS recipes, live-signal patterns, time travel, AI mocks, and troubleshooting.

### ♻️ Changed

#### Runtime

- Internal opaque ids (`id()` / `fx.id()` / run, job, event, instance, and file ids) now use OKID from `okengine/okid` instead of UUID strings — shorter and equally collision-resistant.

- `defaultFn(id)` now emits native OKIDs, and `defaultFn(okid)` is recognized as an id default; the declarative schema surface accepts either.

#### Docs

- Store docs promote Access policies (owner / tenant / scope) and Live queries (`live: true` and `.live(table)`) to dedicated H3s under SQL.

### 💥 Breaking Changes

#### Runtime

- `field.timestamp()` and `field.date()` now infer `Date` objects by default (previously ISO strings) — opt into ISO strings with `{ mode: "string" }`. Drizzle emission pins `mode: "date"`, and `.now()` on default temporals yields `Date` (`$defaultFn(nowDate)`).

- `.default(v)` is now typed against the column's JS type — call sites passing mismatched literals (e.g. `field.integer().default("0")`) fail typecheck.

### 🐛 Fixed

#### Runtime

- `connectPostgres({ pool: { max: 1 } })` opens a dedicated single-connection client instead of the shared pool — vault `rotateMaster` and other manual `BEGIN` workloads no longer hit `ERR_POSTGRES_UNSAFE_TRANSACTION`.

- Vault rotate-lease claim uses plain `FOR UPDATE` (no `SKIP LOCKED`) so a row briefly locked by an audit append is not misread as “lease held by another instance”.

- RLS helper install (`CREATE OR REPLACE FUNCTION oke.*`) is memoized per SQL connection, not per session handle — concurrent identity bags no longer race `pg_proc` with `tuple concurrently updated`.

- Channel default email sender is `oke@localhost.test` (was `oke@localhost`) so out-of-the-box SMTP validation accepts the envelope.

- Concurrent `channel` sends through one transport are serialized so shared SMTP sockets cannot interleave DATA frames.

- `oke doctor` estimates peak file-descriptor need from live signals / SSE routes (G3b-calibrated ~1.5 fds/subscriber) and warns or errors when the process soft limit is too low.

- Test harness channel runtime now inherits templates declared on the app itself (`oke({ channel: { templates } })`) — previously only `boot.channel.templates` overrides reached the harness, so app-declared templates silently dropped out of `t.channels.sent()`.

### Docs

- Root `SECURITY.md` — coordinated disclosure via GitHub private vulnerability reporting (Security tab); README Documentation link.

#### Dev, Keel & create-oke

- `bun install` no longer fails with `failed to link package: okengine@ (link)` — Keel links the monorepo root via `prepare` symlink instead of `"okengine": "file:../.."`, which made Bun hardlink the whole tree and choke on Cursor plan files under `.cursor/plans` (`com.apple.provenance`).

- `bun run verify` — same check jobs as `.github/workflows/ci.yml` (`verify:lint`, `verify:typecheck`, `verify:test`, `verify:gate`, `verify:site`). `bun run ci` still adds budgets and the Keel example.

### 🔒 Security

#### Runtime

- Adversarial audit of `oke.row_passes_policies` fixed two replay divergences: policies scoped `TO <role>` were evaluated without checking role applicability (a non-member policy could widen visibility through the live-query replay path), and INSERT probes picked the USING clause instead of WITH CHECK (fail-closed divergence vs native RLS). Permanent regression gates added to `rls-row-passes-policies.parity.test.ts` (TO-role leak + mixed-clause INSERT); parity re-verified on PGlite and live Postgres 17.

- OAuth mix-up defense (RFC 9700 / RFC 9207): per-provider callback routes, single-use hashed `state`, and issuer pinning on every assertion.

- Unverified provider emails cannot take over existing accounts (GHSA-6g38-8j4p-j3pr class) — Facebook/X/Figma always unverified; Apple string `"false"` stays false.
