# Changelog 0.15

## v0.15.2 — 2026-08-21

### 🐛 Fixed

- oxfmt ignores generated emit (`oke-client.d.ts`, `schema.drizzle.ts`, `flows/generated.ts`) so `oke dev` no longer fails Format on CI.

## v0.15.1 — 2026-08-21

### 🐛 Fixed

- Compiler 200-flow extract budget test no longer dies on Bun's 5s default timeout on GitHub Actions. CI still asserts under 4s after warmup.

## v0.15.0 — 2026-08-21

### ✨ Added

#### Console — Store

- One Gate picker on SQL, browse, and grid edit. Policy sheet Code tab shows `store.schema.policy` plus `pgPolicy`. Policy grid marks `declared` vs `live`. Schema cards show Manifest RLS.

- Resource header shows an RLS chip before PII for SQL tables (on/off from live `relrowsecurity`, same shield language as the tree). Enabled tables with policies show **N RLS**.

- Owner policy templates open a Column select of the table fields (preselect `creator_email` / `owner_email` when present) with PK / FK marks, and rewrite USING / WITH CHECK. Create stays blocked until a column is picked.

- Two-finger click (right-click) a Store row opens the row sheet. Empty grid opens Create policy / index / function / trigger or Insert.

- Row sheet Edit / Save patches editable columns (policy roles, USING, WITH CHECK, command, and table / KV cells).

- Create policy: form X closes the sheet; templates X only closes the templates dock (the shared X no longer sits on templates).

- Create policy SQL / Code dock has the same drag handle as Query / explorer splits so the preview can be resized.

#### Runtime

- `store.schema.policy.gate/owner/scope` and `store.schema.rls()`. `oke db push` installs `oke.*` helpers before drizzle-kit.

- File-tree HTTP routes: `http.get()` plus nameless `flow({ do })` stamp path and `unit.export` from `flows/<unit>/`. `oke()` drains `generated.ts` into `$routes`. Unresolved path is OKE1010; duplicate method+path is OKE1011; unnamed HTTP is OKE1012.

- Tree generate fails when two files declare the same method + path (`list.ts` + `route.ts` both `http.get()` → `GET /notes`). Different methods on one path stay allowed. Boot still refuses leftovers (OKE1011).

### 💥 Breaking Changes

#### Console — Store

- SQL / browse / edit payloads are `{ asGate, asUserId }`. Local-only `asUserId` on the SQL picker is gone — the server stamps the full bag.

#### Console — Units & Call API

- Policy-only invoke no longer mints `userId: "gate:${name}"`. `oke.user()` is empty unless a seeded user is picked. Invoke may return `rls`.

#### Runtime

- Linear / edge match order is static, then `:param`, then `*` — same as Trie and RegExp. A first-registered `/notes/:slug` no longer eats `/notes/archive`.

- User-plane `fx.store` applies RLS on postgres / pglite. Apps that created Console policies and relied on the app role ignoring them now filter.

- Public contract is `oke.gate()` / `oke.user()` / `oke.has_scope()`. Docs and templates no longer teach `current_setting` or `current_user`.

- Special `TO` roles stay unquoted (`public`, `current_user`). Manifest `Table` gains `rls` + `policies`.

- HTTP trigger `.gate.public` is gone. Mark a route open with `.public()`, sibling of `.live()`. `gate.public` stays the element sentinel.

### ♻️ Changed

#### Dev, Keel & create-oke

- Keel and create-oke templates pin the same drizzle `rc5` pair as the framework (`orm@1.0.0-rc.5-169397b`, `kit@1.0.0-rc.5-ab785fc`).

- create-oke Notes (standard / advanced) use the file tree. `app.ts` is `import "@/flows/generated"` plus `oke({ name })` — `.adopt(routes)` is optional. Keel `core.ts` splits by element; the barrel stays `@/core`. `oke ai setup` prefers `src/core/ai.ts` when that file exists.

- `oke dev` Ready board uses aligned name / port columns, and each bound surface (Backend, Console, MCP, Docs MCP) is its own box with the URL and a one-line purpose.

#### Runtime

- Drizzle pin: `drizzle-orm@1.0.0-rc.5-169397b` (npm `rc5`) and `drizzle-kit@1.0.0-rc.5-ab785fc` (kit `rc5`). There is no `1.0.0-rc.5` on the registry.

- User-plane HTTP `fx.store` stamps Gate identity per statement on postgres / pglite. Cron / CDC / signal stay table-owner.

- `oke()` auto-drains `store.kv` / `store.index`, `clock()`, and `gate.policy` / `.scope` / `.rate` the same way as `store.sql` / `vault.secret`. Import the declaring module before `oke()` — no hand-built `stores` / `clocks` / `gate.policies` arrays.

#### Docs

- New Get Started page: Project structure — folders are the URL, reserved leaves, `main` prefix exception, QUERY vs leaves, `[...slug]` client key `"*"`, and `http.resource` in a tree.

- Introduction, Basic Usage, Client, CLI, and element pages point at Project structure so `http.get("/…")` + `flow("unit.action")` is no longer taught as the only identity.

- Project structure: `_` files are importable but not routes; match order is static → `:param` → `*`; generate-time method+path collision.

- Bumped site dependencies: fumadocs to `16.14.5` / MDX `15.3.0`, Next to `16.3.1`, plus patch/minor updates for `@base-ui/react`, lucide, postcss, and `@types/node`.

#### Console — Store

- Store tree toolbar shows SQL, KV, Files, and Index icons to show or hide each facet. The eye menu and per-band Hide control are gone.

- Query Run is play + label only. ⌘ Enter stays on the tooltip and the run menu.

- Owner / Gate templates and the policy Code dock use `oke.user()` / `oke.gate()` / `oke.has_scope()`.

- Store Query results fade in once per completed run (180ms EASE_OUT, translateY 4px; reduced-motion opacity 120ms).

#### Console — Flows & traces

- Overview Traces Advanced filters now reveal/collapse with the existing AgentDisclosure clip-path (220ms open / 140ms close, EASE_OUT).

#### Dev, Keel & create-oke

- `oke db seed` is a separate command (`intro` / confirm / `outro`). `oke dev` does not ask to seed — not every project has a seed. The live controls add `s` to run that command as a child (`oke db seed --force`), not inside the `oke dev` process.

- Keel (and store resource tests) generate Zod from tables via `drizzle-orm/zod`. The separate `drizzle-zod` package is gone.

- Keel and create-oke templates are `oke({ name })` — stores, secrets, gates, clocks, and channel templates auto-register from `@/core`.

### 🐛 Fixed

#### Console — Chrome

- Key caps on primary buttons use the button ink so chords stay readable.

#### Console — Store

- Query console replaces a leftover default `SELECT` when that table is not in the live store, and seeds a random live table (not always the first).

- KV browse `value` fills leftover grid width (same as SQL `comment`).

- Files PDF preview was a blank iframe — CSP `frame-src 'self'` blocked the blob URL. `frame-src` / `img-src` / `media-src` now allow `blob:`.

- Resource header no longer repeats a singleton ref (`kv:reminders · kv:reminders` → `kv:reminders`). SQL still shows `sql:db · sql:tasks`.

#### Console — Units & Call API

- Extract expands `z.object` and `drizzle-orm/zod` (`createSelectSchema` / insert / update, `tableZod().select`) into Manifest JSON Schema so Call API Fields and the contract Request / Response lists populate instead of "Schema not expanded in Manifest."

- Mutation receipts (`clock.run-now`, store edit, vault write, replay, channel send-test, …) return `at` as ISO-8601 UTC instead of epoch ms (`1787305011525` → `2026-08-21T09:36:51.525Z`).

- Call API no longer seeds a JSON body on GET / HEAD / DELETE. Path tokens (`:id`) stay in Path params; leftover GET fields are Query params. `GET /tasks/:id` is path-only — the duplicate Body `id` is gone.

#### Runtime

- `$routes` from `generated.ts` accepts cron / signal / call-only flows — `AppRouteMap` no longer requires `method`/`path` on every leaf.

- Pathless `http.get()` types resolve `HttpPathPending` in the trigger namespace (verbatim type import).

- PGlite RLS stamp is split statements (`SET LOCAL ROLE oke_app`, `set_config`) — a multi-command batch is rejected by PGlite's prepared `query` path. Concurrent identities on the shared connection are serialized.

- Postgres RLS stamps `reserve()` one Bun.SQL slot, then `BEGIN` / `SET LOCAL` on that slot. `begin()` plus parent `unsafe()` was deadlocking PgDog (`checkout timeout`). Store, journal, clock, and instances share one pool of 8; PgDog `pool_size` is 20.

- `oke.*` helpers install again: `toPostgresParams` no longer rewrites `jsonb ?` into `$1` when there are no bound values, and `oke.has_scope` uses `jsonb_exists`.

- Creating schema `oke` no longer steals domain tables: search_path is `public, oke`, and leftover `oke.<table>` rows move to `public`.

- `fx.store(db).select().where()` / `.orderBy()` compile Drizzle `eq` / `and` / `or` / `like` / `asc` again against the pinned `drizzle-orm@1.0.0-rc.5-169397b` — that snapshot stores `StringChunk.value` as a string, not `string[]`.

#### Dev, Keel & create-oke

- Keel KV (`drafts`, `reminders`, `view-prefs`, `webhooks`) is `{ durable: true }` and seed writes all four, so Console Store browse is not empty after Redis recreates. Seed logs `keys N` for `kv.set`.

- `recurring.spawn` (and GitHub / Slack / form intake) call `tasks.create` by name so the Manifest stamps `effects.calls` — aliased `fx.call(createTask)` was inferred as `createTask` and threw OKE1007 every hour.

- `oke db push` treats drizzle-kit `rename_or_create` as create and retries, so a first-time Keel schema no longer fails `missing_hints`. Destructive `confirm_data_loss` still stops.

- `oke db push` only manages schema `public` (`schemaFilter`), so it does not try to drop `oke` / `oke_console`.

#### Docs

- Homepage starter snippet reads `flows/main/route.ts` after the tree split removed `main/index.ts`.
