v0.9.1
๐ฅ Breaking Changes
- Breaking-ish: now refused โ a backslash in
fragment/rawtemplate text is OKM1125. Pass the value as an interpolation (B-01, D287). - Breaking-ish: now refused โ an unknown key on
insert,update, upsert /onConflict, or first-or-create is OKM1120 and names the key and the table (B-39, D291). - Breaking-ish: now refused โ a finished statement with more than 65,535 parameters is OKM1126 (count and limit in the message) instead of a retryable
unavailable(B-40, D292). - Breaking-ish: now refused โ an unknown CLI flag is an error;
okm <command> --helplists that command's flags (B-26, D289). - Breaking-ish: now refused โ an
updatethat would set a tree parent to the row itself or to a descendant is OKM1120 whenwhereis the primary key (B-10, D295).
๐ Security
- A backslash in a composed fragment can no longer desync the literal guard and escape a tenant filter (B-01, D287).
- A unique, foreign-key, or check failure on a table with a sensitive column no longer puts the value in
error.cause(detail, parameters,where, andinternalQuerystay off). Tables without sensitive columns keep today's cause.includeValuesremains the explicit opt-in (B-33, D291). - With
defineConfig({ roles }), managed functions revokeEXECUTEfromPUBLICand grant it only to the app role, so the reporting role cannot execute them (B-31, D293). Provider-specific role checks (RDS, Cloud SQL, Supabase) follow in M-4.
๐ Fixed
dialects
filters()OKM1123 uses the calling table's own columns for allow/sort, and replaces per-table hidden marks when the same SQL name is redefined, so a prior.hidden()no longer poisons later suites that reusetasks.title(and the same pattern for relation targets).
runtime
- A statement with more than 65,535 parameters fails with OKM1126 (count and limit in the message) instead of a retryable
unavailable. The limit is for the whole statement, including filters andinList(B-40, D292). Split from the write-safety work on #339 when the combined change grew the featureless app by more than 100 B. - An
updatethat would set a tree parent to the row itself or to a descendant is OKM1120 whenwhereis the primary key (B-10, D295). - A throw from a custom
routing.selectkeeps anOkmError's kind; a plain throw becomes kindinvalidinstead ofdriver(B-35, D295).
adapters
- Bun.sql no longer parks a reserved handle for the next checkout, so concurrent scoped units after a backend kill keep separate sessions and tenant settings (B-03, D288).
- A reset or release failure after a statement or
COMMITcompleted destroys the connection and does not fail the call on Bun.sql, node-postgres, or Neon, so a committed write is reported as committed andafterCommitstill runs (B-04, D288). - node-postgres maps
Client has encountered a connection error and is not queryableto a lost connection (CONNECTION_CLOSED), matching Bun.sql's message-only closed texts (D288). - Bun.sql
reserve()stamps code-less closed-socket texts (Connection closed,connection must be a PostgresSQLConnection) with SQLSTATE08006, so a checkout that fails before the reserved-handle guard classifies asunavailableinstead ofdriver(B-03, D288). - postgres.js caps reconnect backoff under 1 s with jitter, defaults
timeouts.acquireto 10 s (OKM1846), swallowsnextWriteon a null socket (Bun and Node), and rebuilds the pool so a kill storm's first OK read arrives within 3 s (B-02, B-43, D294). Other uncaught exceptions still print and leave a non-zero exit sookm migrate check/applyrefusals are not reported as success on Bun. - node-postgres defaults
timeouts.acquireto 10 s and keeps an idle/checked-out clienterrorlistener that logs on the notice path without throwing, so a backend kill of an idle client does not crash Node (B-44, D294). - A node-postgres call with
timeoutorsignalremoves its checkouterrorlistener, so repeated timed calls do not stack listeners on a pooled client. A call that reaches its deadline while waiting for a connection is refused and does not run. A cancel that does not settle destroys that client, so the pool can serve the next call after a kill storm.
tooling
- CI copies the milestone from
Closes #Nonto the pull request beforelint / pull request, so agents that cannot PATCH milestones still pass D206. - The sticky migrate-plan comment matches the marker and the bot author, so another author's marked comment is not edited (B-22, D295).
okm driver testdrops leftoverokm_*tables after each wire and error case, refuses Bun below1.4.0, and never reports an unrun case aspass(B-05, B-06, B-42, D295).okmodel/testingfactories andisolation()work undercompositeTenancy(); concurrent creates no longer false-positive as a factory cycle; matviews are refreshed inisolation()and documented otherwise (B-32, B-28, B-34, D295).- The Bun.sql kill-storm test (B-03) retries post-storm scoped reads on
unavailable/closed (bounded) so a dying reserved handle after the storm does not fail CI, without relaxing stormshort/leaks/readOnly/nestedasserts. okm pushplans from the live catalog and applies each change under a freshpush-<n>id, so a second push is no longer skipped (B-29, D289).- When the schema hash moves with no DDL (an external table the dependent already verified),
okm pushandokm migrate applyre-stampokm_metainstead of leavingconnect()on OKM1520 (B-21, D289). okm migrate checkkeeps a trigger's function in the logical namespace, so schemas withtimestamps({ enforce: "trigger" })or hand-written triggers no longer fail OKM1020 (B-24, D289).okm checkandokm pushreprint domain checks on the connected server before planning, so a non-canonical author check is not permanent live drift (B-36, D289).- The guide's
rolesblock applies as a superuser and as aCREATEROLEschema owner: managed roles are created beforeSET ROLE, schema ownership is transferred when possible, and a failed role unit stays re-runnable with a clear privilege error. On Postgres 15, apply grants itself membership afterCREATE ROLE(which leaves none); on Postgres 16+ it grantsWITH SET TRUE(B-30, D293). - Migrate strips the
pgbouncerquery parameter before the URL becomes a startup parameter; other pooler hints are not interpreted (B-25, D293). Provider-specific role-admin checks (RDS, Cloud SQL, Supabase) follow in M-4. - The pooler pid probe uses eight reads on the apply session (OKM1854 when the backend pid changes). Warm-and-hold for LIFO PgBouncer is kept out of apply/seed so single-connection targets do not hang; URL heuristics still refuse typical pooler hosts and ports (B-41, D293).
- The type-change recipe's temporary
IS NOT NULLvalidate is no longer OKM1531 (B-37, D289). - An unknown CLI flag is an error;
okm <command> --helplists that command's flags (B-26, D289). - Backfill progress prints a 1-based step index (B-27, D289).
okm pullandokm import drizzlewrite foreign keys with the exported table binding, keep file stems unique on case-insensitive volumes, and never write a Windows-reserved stem (con,aux,nul,com1, โฆ). A column__proto__is a computed key. Composite primary-key columns stay not null on Drizzle import. Missingoxfmtprints a notice and still writes the report.okm ext scaffoldincludes composite types (B-14 to B-19, B-38, D290).
docs
- Tree, testing, driver-test, and Action docs cover cycle refusal, composite factories, minimum Bun, cleanup, and sticky-comment author matching (D295).
- Known limits record that Bun.sql does not park reserved handles, that a post-commit reset failure does not fail the call, and that a send-without-result is OKM1401 with no
afterCommit(D288). okm pushdocs say it applies the live schema diff aspush-<n>, and known-limits cover external re-stamp and domain-check sealing (D289).- Sensitive docs cover redaction in logs, errors,
cause, and spans; writes docs cover unknown keys (D291). - Queries and the error reference document OKM1126 when a finished statement exceeds 65,535 parameters (D292).
- Guide roles privileges, production.md
--target/ status / check behavior, and known-limits pooler notes (DM-2, DM-3, D293). - Known limits, README, guide, spec, and handbook pages match the code after the 0.9.1 fixes: Temporal polyfill on Node 22/24,
okm dev,okmodel/safety, redaction, untypedrawand raw projection (B-07, B-08), minimum Bun,okmodel.config.ts,listenas a driver capability only, catalog export vsdescribe, backfill step numbering, and a Not tested section (DM-1 to DM-12, D296).