From 01ec4de364f267eeb9172a7fe0f3cb4244b4e71a Mon Sep 17 00:00:00 2001 From: Aaron Boodman Date: Tue, 16 Jun 2026 11:45:19 -1000 Subject: [PATCH] wip --- .agents/skills/release-notes/SKILL.md | 70 ++++++++++--- .releases/1.7/commits.md | 144 ++++++++++++++++++++++++++ contents/docs/otel.mdx | 19 ++-- contents/docs/release-notes/1.7.mdx | 66 ++++++++++++ 4 files changed, 277 insertions(+), 22 deletions(-) create mode 100644 .releases/1.7/commits.md create mode 100644 contents/docs/release-notes/1.7.mdx diff --git a/.agents/skills/release-notes/SKILL.md b/.agents/skills/release-notes/SKILL.md index 51f7439d..a8a63984 100644 --- a/.agents/skills/release-notes/SKILL.md +++ b/.agents/skills/release-notes/SKILL.md @@ -30,23 +30,67 @@ Produce a release note draft that is intentionally over-inclusive so a human can ## Workflow 1. Determine commit range between release tags: - - `git log --oneline --no-merges ..` -2. Classify commits using conventional commit prefixes: + - First list every non-merge commit in the raw range: + - `git log --reverse --oneline --no-merges ..` + - Keep this as the audit source until the human has reviewed categorization. +2. Remove commits already included in the previous release through cherry-picks: + - Find the common ancestor between previous release and target: + - `git merge-base ` + - Inspect commits on the previous-release side after that ancestor: + - `git log --reverse --format='%h%x09%s%n%b%n---END---' ..` + - Look for `-x` cherry-pick trailers such as `(cherry picked from commit )`. + - Also use patch-equivalence to catch cherry-picks whose lockfiles or package-manager files differ: + - `git log --right-only --no-merges --cherry-mark --format='%m%x09%h%x09%s' ...` + - Treat `=` commits as already present in the previous release and categorize them as `skip`, unless the target commit contains materially different user-facing changes. + - When a previous-release maintenance commit names a target commit in its cherry-pick trailer, categorize that target commit as `skip`. +3. Run the protocol compatibility check immediately: + - Find protocol constants in mono before drafting any notes. + - Check both previous release and target values, for example: + - `git show :packages/zero-protocol/src/protocol-version.ts` + - `git show :packages/zero-protocol/src/protocol-version.ts` + - Ensure the target version's minimum supported sync protocol is `<=` the previous release's `PROTOCOL_VERSION`. + - If compatibility fails, this is a release-blocking breaking change. Record it loudly in `.releases/./commits.md` with `BREAKING`, and mark the responsible commit `BREAKING` if it can be identified. + - If compatibility passes, still record the result in `.releases/./commits.md` so later release reviews do not need to rediscover it. +4. Categorize every commit and flag potential breaking changes before drafting. Use only these categories: + - `perf` + - `feature` + - `fix` + - `skip` + - Also identify potential breaking changes in every commit, including skipped/internal-looking commits. + - Look early for API renames/removals, env var/config changes, default behavior flips, migration requirements, protocol changes, package export/import changes, dependency/peer dependency changes that can affect install/runtime behavior, and commit text containing "breaking". + - Record breaking-change status separately from category. + - Use `-` for commits that are not believed breaking. + - Use `MAYBE` for commits that could be breaking and need human review; explain why in the note. + - If a commit is believed to be breaking, make it extremely visible with `BREAKING`. This should be rare; Zero release planning aims to avoid breaking changes. + - Treat breaking-change detection as an early warning system for ongoing release review, not something to defer until the final draft. +5. Present the categorization to the human for review before writing release notes: + - Use a Markdown table with `Commit`, `Category`, `Breaking?`, and `Note`. + - The note should be a few sentences when useful: summarize what changed, why the category was chosen, whether it was skipped due to cherry-pick, revert, internal-only scope, or lack of user-facing impact, and why it is or is not a potential breaking change. + - Prefer `skip` for CI, release tooling, benchmark-only, sample-only, dependency hygiene with no identified user-facing effect, reverted changes, and commits already in the previous release. + - Use `fix` for customer-observable behavior even when the commit is labeled `chore`, e.g. packaging changes that prevent duplicate runtime dependencies from breaking checks like `Pool instanceof`. + - Use `perf` for fixes whose primary user-facing value is measured speed/CPU/allocation improvement. + - Use `feature` for new user/operator/debugging capability. + - Reclassify suspicious commits while building the table: + - Include `chore` commits that look user-facing, behavior-changing, protocol-affecting, package/export-affecting, or crash/fix related. + - Check dependency update commits when they affect runtime, install, protocol, query correctness, or performance-critical packages. Look at upstream changelogs when needed. + - Treat the `Breaking?` column as the breaking-change pass: + - Look for API renames/removals, env var/config changes, behavior flips, migration requirements, protocol changes, package export/import changes, dependency/peer dependency changes, and semantically breaking behavior even if unlabeled. + - Also scan commit text for "breaking". + - Flag performance follow-ups early for commits that change query compilation, index use, dependency implementations, hot loops, or runtime semantics. Put the performance concern in the note or open questions even if the commit category is `fix`. +6. Save the reviewed categorization in the docs worktree before drafting: + - Use a stable release working-state directory under `.releases/./`, for example `.releases/1.7/commits.md`. + - Include release version, previous tag, target, merge base, the exact commands used, the reviewed table, potential breaking changes, and any unresolved questions. + - On later sessions, read this file first and evolve it instead of redoing the whole commit audit. +7. After human review of the categorization, classify the non-skipped commits using conventional commit prefixes as a starting point: - `feat` -> Features - `fix` -> Fixes - `perf` -> Performance (if meaningful) - `chore` -> ignored by default -3. Reclassify suspicious commits: - - Include chore commits that look user-facing, behavior-changing, protocol-affecting, or crash/fix related. - - Check dependency update commits (especially performance-critical packages like `compare-utf8`, `litestream`, etc.) - look at the upstream changelogs to see if they contain notable perf or fix items. -4. Breaking change pass (separate from type labels): - - Look for API renames/removals, env var/config changes, behavior flips, migration requirements, protocol changes. - - Also scan commit text for "breaking" or semantically breaking behavior even if unlabeled. -5. Protocol compatibility check: - - Find protocol constants in mono. - - Ensure `MIN_PROTOCOL_VERSION` in the version being documented is `<=` `PROTOCOL_VERSION` in the previous release version. - - Flag any mismatch in the draft. -6. Build draft release notes in the latest format used in this repo: +8. Before drafting, revisit the reviewed table: + - Confirm all non-skipped commits are represented or intentionally omitted. + - Re-check any `MAYBE` or `BREAKING` rows and summarize the decision in the draft or in the saved release state. + - Re-check any performance follow-ups recorded in `.releases/./commits.md`. +9. Build draft release notes in the latest format used in this repo: - Before drafting, read `contents/docs/release-notes/0.26.mdx` as the canonical long-form style reference to avoid format drift. - Frontmatter with `title` and `description` - `## Installation` diff --git a/.releases/1.7/commits.md b/.releases/1.7/commits.md new file mode 100644 index 00000000..08ca7502 --- /dev/null +++ b/.releases/1.7/commits.md @@ -0,0 +1,144 @@ +# Zero 1.7 Release Commit Categorization + +- Release: Zero 1.7 +- Previous release tag: `zero/v1.6.1` +- Target: `main` +- Monorepo path used: `/Users/aa/work/mono` +- Merge base: `9d447833ca69cedc9fd32e5a228ce285e3a8af91` + +## Commands Used + +```bash +git -C /Users/aa/work/mono log --reverse --format='%h%x09%s' --no-merges zero/v1.6.1..main +git -C /Users/aa/work/mono log --reverse --format='%h%x09%s%n%b%n---END---' 9d447833ca69cedc9fd32e5a228ce285e3a8af91..zero/v1.6.1 +git -C /Users/aa/work/mono log --right-only --no-merges --cherry-mark --format='%m%x09%h%x09%s' zero/v1.6.1...main +``` + +## Protocol Compatibility Check + +- Status: PASS +- Previous release `PROTOCOL_VERSION`: `51` +- Target `PROTOCOL_VERSION`: `51` +- Target `MIN_SERVER_SUPPORTED_SYNC_PROTOCOL`: `30` +- Compatibility rule: target minimum supported sync protocol must be `<=` previous release protocol version. +- Result: `30 <= 51`, so this is not a breaking change. +- Note: `393695512` updates protocol-version expectations in tests, but the actual protocol constants in `packages/zero-protocol/src/protocol-version.ts` are unchanged between `zero/v1.6.1` and `main`. + +## Categorization + +| Commit | Category | Breaking? | Note | +|---|---|---|---| +| `8916f8001` | perf | - | Batches flip-join requests instead of issuing many separate fetches. This improves relationship-heavy query performance substantially in the benchmark from the PR. | +| `aee683c2b` | fix | - | Handles WebSocket close code 1009 without reconnecting forever and resending the same oversized message. It surfaces a clearer error and abandons the stuck client group. | +| `e5bf8bd4f` | skip | - | Already in 1.6.1 as cherry-pick `e3e63d4ef`. Adds backoff when CVR purging fails, but should not be repeated in 1.7 notes. | +| `7a1d2fea7` | skip | - | Already in 1.6.1 as cherry-pick `df3aff288`. Makes zero-cache abort when ChangeDB CDC tables are missing. | +| `257da8234` | perf | - | Avoids O(N²) accumulation in `Debug.rowVended` by pushing into the existing array. This matters for large debug/analyze workloads. | +| `359db1416` | skip | - | Benchmark-only change to use ZQL for flip-join benchmarks. No direct product behavior change. | +| `fc56a7338` | fix | - | Inspector/analyze-query now uses the actual table-source query plan. This makes diagnostics more accurate. | +| `d10925ad2` | perf | - | Replaces queue `Array.shift`-style behavior with an O(1) ring buffer. This reduces CPU under heavy replication queue load. | +| `279df61ac` | skip | - | Removes unused production permissions helper. Internal cleanup. | +| `7954d6b49` | skip | - | npm audit fix. No specific Zero behavior called out. | +| `7bb253814` | skip | - | OpenTelemetry dependency bump. No specific user-facing change identified. | +| `10e727a03` | skip | - | Replaces Vercel node types with local interfaces in otel-proxy. Internal refactor. | +| `d2c9d4af8` | skip | - | Pins GitHub Actions. CI security hardening only. | +| `90df9a375` | skip | - | Dependency updates for Vite/database libraries. No specific product change identified. | +| `e7bda36db` | skip | - | Allows Vite minor upgrades. Dependency maintenance. | +| `63b52e775` | skip | - | Fixes Vite version in lockfile. Internal dependency consistency. | +| `4766675da` | skip | - | Adds vulnerability-detection script. Internal security tooling. | +| `01bd90fa8` | skip | - | npm audit fix. No specific Zero behavior called out. | +| `4ff19849b` | skip | - | Removes legacy assistant workflow. CI cleanup. | +| `cb75a03f4` | skip | - | Updates JS checks workflow. CI-only. | +| `68bb5f6a6` | skip | - | Updates file-size workflows. CI-only. | +| `4029bc22f` | skip | - | Updates benchmark workflows. CI-only. | +| `a05b2bb3c` | skip | - | Updates mirror workflow. CI-only. | +| `c37ac92b4` | skip | - | Updates deploy workflows. CI-only. | +| `052dda116` | skip | - | Updates canary release flow. Release infrastructure. | +| `c4e6db1ce` | skip | - | Migrates mono from npm to pnpm. Important internally, but not a published Zero behavior change. | +| `36f26d619` | skip | - | Removes package-lock helper script. Internal tooling. | +| `15e3d6b9f` | skip | - | Moves Replicache perf code. Internal benchmark organization. | +| `bd7465cf1` | skip | - | Updates Docker dependencies. Security/image maintenance. | +| `9f9f82660` | skip | - | Scopes canary-release OIDC token. CI security. | +| `7cc08742d` | skip | - | Moves SST into pnpm. Internal tooling. | +| `ba78376d9` | skip | - | Fixes CI permissions and pnpm install. CI-only. | +| `6e53b5b92` | skip | - | Removes `npx` usage from CI/scripts. Internal tooling. | +| `90159039a` | skip | - | Reworks canary release workflow with dry-run support. Release infrastructure. | +| `8e33dd079` | skip | - | Docker login/version parsing workflow work. Release plumbing. | +| `9a0147315` | skip | - | Docker login/version parsing workflow work. Release plumbing. | +| `b877b7abf` | skip | - | Docker login/version parsing workflow work. Release plumbing. | +| `d44fa8ca3` | skip | - | Docker login/version parsing workflow work. Release plumbing. | +| `66852ea85` | skip | - | Changes release process to clone instead of copy. Internal release tooling. | +| `d5d3d57a3` | skip | - | Adjusts release cloning behavior for CI/local. Internal release fix. | +| `3ba9f26e5` | skip | - | pnpm release-age exclusions/version overrides. Internal package-management setup. | +| `f02f76915` | skip | - | Adds benchmark JSON output and silent mode. Dev benchmark tooling. | +| `509f7b027` | skip | - | Updates npm references to pnpm. Internal config/docs. | +| `57b1a4b09` | skip | - | Singular flag query-hash attempt, later reverted. Do not note reverted behavior. | +| `257f2152a` | skip | - | Docker dependency/security cleanup. Image maintenance. | +| `e707eaf11` | skip | - | Stops release script from mutating app package manifests. Release-process fix. | +| `f35216528` | skip | - | Removes zbugs deploy. Internal sample app CI. | +| `7d260572c` | skip | - | Restores flat published `out/` layout after pnpm migration. Skipping after review because this was internal pnpm migration/build fallout rather than a 1.7 user-facing change to call out. | +| `f1ac318c0` | skip | - | Iterator helper for lint upgrade. Internal. | +| `035549bc6` | skip | - | Removes `tsx` usage. Internal tooling/runtime cleanup. | +| `31a027f1a` | fix | NO | Externalizes optional peer deps so `pg`, `react`, and `solid-js` are not bundled into Zero output. This prevents duplicate installed copies that can break customer-observable runtime behavior, including `Pool instanceof` checks and React single-instance assumptions. Reviewed as non-breaking: although package peer dependency/install behavior technically changed, the previous behavior was broken enough that users should not reasonably depend on it. | +| `820f17fa5` | feature | - | Adds `replication.last_total_lag` gauge. Gives operators a new metric to distinguish real lag from stalled lag-report delivery. | +| `b2474686b` | skip | - | Uses pnpm to gate transitive install scripts in Docker build. Security hardening. | +| `9bbb0509c` | skip | - | Docker pnpm 11 work. Build plumbing. | +| `cf1e3eb31` | skip | - | zbugs access-key debug logging. Sample/internal. | +| `e4358fb90` | skip | - | Adds GitHub Actions security analysis. CI security. | +| `b80cced16` | skip | - | Bumps Playwright. Test dependency maintenance. | +| `8b29a2d26` | skip | - | Hardens release asset workflow. CI/release security. | +| `a684c0c26` | skip | - | Hardens benchmark workflows. CI security. | +| `7e511179a` | skip | - | Fixes zizmor findings. CI security. | +| `16ec13edd` | skip | - | Scopes release/mirror workflow secrets. CI security. | +| `347abab47` | skip | - | Removes Bencher/file-size workflows. CI cleanup. | +| `3956a0b41` | skip | NO | Splits permissions internals into a private `zero-permissions` workspace package to break cycles. Public `@rocicorp/zero` exports for `definePermissions`, `ANYONE_CAN`, `NOBODY_CAN`, and permission types remained in place; the removed `zero-schema/src/mod.ts` was in a private workspace package, not a published public import path. | +| `811a1d9d0` | skip | - | Cross-package import refactor, later unwound. Internal. | +| `393695512` | skip | - | Protocol-version test expectation update. Verified separately in the protocol compatibility check: the actual protocol constants are unchanged between `zero/v1.6.1` and `main`, so this is not believed breaking. | +| `699728e84` | skip | - | pnpm 11.3 pins. Internal tooling. | +| `11a4c358d` | skip | - | Reverts singular query-hash fix. Revert bookkeeping. | +| `a39469416` | fix | - | Prevents singular and plural queries with the same AST from sharing a client view. That sharing was incorrect because the views have different semantics. | +| `9960407d6` | fix | - | Fixes a regression where removing a query could trigger an assertion. User-visible as a possible client crash/assert. | +| `ae6cf8b94` | skip | - | React 19 upgrade to fix Vercel build. Build maintenance. | +| `5d2fd7ef4` | skip | - | Already in 1.6.1 as cherry-pick `4ce15e597`. Inspector compatibility with older clients. | +| `2f466f6f6` | skip | - | zbugs import-path refactor. Sample/internal. | +| `91257a51e` | skip | - | Reverts/fixes cross-package import refactor. Internal. | +| `2ce4ee3e6` | skip | - | Removes unused Replicache CI workflow. CI cleanup. | +| `6126dc063` | skip | - | CODEOWNERS for zbugs. Repo governance. | +| `58bb5a9c0` | skip | - | Staged npm releases for maintainer approval. Release process. | +| `feee2be78` | fix | - | `LIKE`/`ILIKE` matching uses dotall behavior instead of multiline. Fixes query-result mismatches for strings containing newlines. | +| `517f29f30` | skip | - | Adds relationship-heavy ArrayView benchmark. Benchmark-only. | +| `79828be75` | skip | - | Import-path refactor, later reverted. Internal. | +| `e5f5a56b7` | skip | - | Reverts import-path refactor. Revert bookkeeping. | +| `8ec146799` | fix | - | Range filters now use UTF-8 ordering to match SQLite/Postgres ordering. Fixes string comparison correctness. | +| `8e46be85b` | skip | - | CODEOWNERS approval workflow hardening. CI/governance. | +| `5438a8bb1` | feature | NO | Relands immutable `applyChange` without the eager-expansion regression. Improves React/Solid reactivity and reference stability for unchanged subtrees. Reviewed as non-breaking: it could affect consumers relying on accidental mutation of query result objects or previous object identity behavior, but that behavior was not something users should reasonably rely on. Keep flagging similar result-semantics changes for review. | +| `ff587d7be` | fix | MAYBE | Makes SQLite replica `LIKE`/`ILIKE` behavior match Postgres/IVM more closely. Precise behavior changes: plain `LIKE`/`NOT LIKE` becomes case-sensitive on the SQLite replica, so patterns like `a%` no longer match uppercase `A...`; `ILIKE`/`NOT ILIKE` now compile as `lower(left) LIKE lower(right)` instead of reusing bare SQLite `LIKE`; and all `LIKE`/`ILIKE` operators now emit `ESCAPE '\'`, so patterns like `100\%` and `a\_b` treat `%` and `_` literally. Might be breaking because query results can change for apps that relied on the previous SQLite-divergent matching behavior. Needs deeper follow-up before final release notes, including potential performance/index-use impact of `PRAGMA case_sensitive_like = ON`, `lower(...) LIKE lower(...)`, and explicit `ESCAPE`. | +| `3e6ed598c` | skip | - | Updates action pins. CI security. | +| `800f6acff` | skip | - | Already in 1.6.1 as cherry-pick `543e649f6`. Improves write worker errors for production debugging. | +| `fdd8278f3` | skip | - | Already in 1.6.1 as cherry-pick `9d3fb4303`, and release-tooling only. Uses worktrees for release clone. | +| `5a04230cd` | skip | - | Adds transaction-batching ArrayView benchmark. Benchmark-only. | +| `572f1ae4b` | perf | - | Adds transaction-scoped copy-on-write for multi-change transactions. Reduces allocation overhead and shows around 2x wins for large transactions. | +| `dc69d2232` | fix | MAYBE | Adopts `zero-sqlite3` with self-contained Unicode `lower()`/`upper()` mappings, which completes the `ILIKE` behavior introduced by `ff587d7be`. Precise behavior change: SQLite-replica `ILIKE` now matches non-ASCII case variants such as `MÜLLER` vs `müller`, accented Latin, Cyrillic, and Greek because both sides are lowered with Unicode-aware mappings. It is not full Unicode case folding; cases like `straße` vs `STRASSE` still do not match. Might be breaking because non-ASCII `ILIKE` query results can include rows that previously did not match. Needs performance follow-up because Unicode-aware `lower()` on both operands may affect `ILIKE` query cost and index use. | +| `2b76eee35` | skip | - | Already in 1.6.1 as cherry-pick `50bb87536`. Adds analyze CLI `--join-plans`, but not new for 1.7. | +| `4b447e11a` | skip | - | Already in 1.6.1 as cherry-pick `98a41b323`, though patch differs due lockfile/package-manager differences. `zero-sqlite3` 1.1.2 install/build fix. | +| `bfa64ab23` | skip | - | Already in 1.6.1 as cherry-pick `814288531`. Logs SQLite index creation during initial sync. | +| `1c3150de4` | skip | - | Already in 1.6.1 as cherry-pick `b59292a29`. Allows anonymous analyze CLI usage. | +| `f8571f0d4` | skip | - | Fixes latest promotion checks in release tooling. Not product release-note material. | + +## Current Release-Note Candidate Set + +- perf: `8916f8001`, `257da8234`, `d10925ad2`, `572f1ae4b` +- feature: `820f17fa5`, `5438a8bb1` +- fix: `aee683c2b`, `fc56a7338`, `31a027f1a`, `a39469416`, `9960407d6`, `feee2be78`, `8ec146799`, `ff587d7be`, `dc69d2232` + +## Potential Breaking Changes + +- `31a027f1a`: package peer dependency/install behavior changed to avoid duplicate bundled runtime dependencies. +- `ff587d7be`: `LIKE`/`ILIKE` query results can change to match Postgres/IVM semantics. +- `dc69d2232`: non-ASCII `ILIKE` query results can change due to Unicode-aware case mapping. + +## Open Questions + +- Confirm whether `5438a8bb1` should be framed as a feature, perf/reliability improvement, or omitted from the public release notes. +- Confirm whether inspector/analyze-query diagnostics should be grouped together or listed as separate fixes. +- Dig deeper into `ff587d7be` before final notes: decide whether SQLite replica `LIKE`/`ILIKE` correctness changes should be called out as a breaking-change risk, an upgrade note, or just a fix. +- Investigate performance impact of the LIKE/ILIKE changes in `ff587d7be` and `dc69d2232`, especially whether `lower(left) LIKE lower(right)`, explicit `ESCAPE`, or Unicode-aware `lower()` affects SQLite index use or hot query latency. diff --git a/contents/docs/otel.mdx b/contents/docs/otel.mdx index f40a86ef..2b902319 100644 --- a/contents/docs/otel.mdx +++ b/contents/docs/otel.mdx @@ -140,15 +140,16 @@ This callback is called before sending WebSocket messages that trigger API serve ### zero.replication -| Metric | Type | Unit | Description | -| -------------- | ------- | ---- | -------------------------------------------------------------------------------------- | -| `upstream_lag` | Gauge | ms | Latency from sending a replication report to receiving it in the stream | -| `replica_lag` | Gauge | ms | Latency from receiving a replication report to it reaching the replica | -| `total_lag` | Gauge | ms | End-to-end replication latency. Grows as an estimate if the next report hasn't arrived | -| `events` | Counter | | Number of replication events processed | -| `transactions` | Counter | | Count of replicated transactions | -| `shadow-sync-runs` | Counter | | Number of [shadow initial-sync](/docs/zero-cache-config#shadow-sync-enabled) runs. Has a `result` attribute: `success`, `error` | -| `shadow-sync-duration` | Histogram | s | Wall-clock duration of a shadow initial-sync run. Has a `result` attribute: `success`, `error` | +| Metric | Type | Unit | Description | +| ---------------------- | --------- | ---- | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| `upstream_lag` | Gauge | ms | Latency from sending a replication report to receiving it in the stream | +| `replica_lag` | Gauge | ms | Latency from receiving a replication report to it reaching the replica | +| `total_lag` | Gauge | ms | End-to-end replication latency. Grows as an estimate if the next report hasn't arrived | +| `last_total_lag` | Gauge | ms | End-to-end latency from the most recently received replication report. Unlike `total_lag`, it does not grow when replication reports stop arriving. | +| `events` | Counter | | Number of replication events processed | +| `transactions` | Counter | | Count of replicated transactions | +| `shadow-sync-runs` | Counter | | Number of [shadow initial-sync](/docs/zero-cache-config#shadow-sync-enabled) runs. Has a `result` attribute: `success`, `error` | +| `shadow-sync-duration` | Histogram | s | Wall-clock duration of a shadow initial-sync run. Has a `result` attribute: `success`, `error` | ### zero.sync diff --git a/contents/docs/release-notes/1.7.mdx b/contents/docs/release-notes/1.7.mdx new file mode 100644 index 00000000..266cb9ee --- /dev/null +++ b/contents/docs/release-notes/1.7.mdx @@ -0,0 +1,66 @@ +--- +title: Zero 1.7 +description: Query Correctness and Performance +--- + +## Installation + +```bash +npm install @rocicorp/zero@1.7 +``` + +## Overview + +Zero 1.7 is currently shaping up as a query correctness and performance +release. The largest user-visible changes are around making query evaluation +more consistent across Postgres, the SQLite replica, and the in-memory JS query +engine. + +There are still a few open review items before this note is final, especially +around the behavior and performance impact of the `LIKE`/`ILIKE` changes. + +## Features + +- [**Replication lag diagnostics:**](/docs/otel#zeroreplication) Added a `replication.last_total_lag` gauge so operators can distinguish actual replication lag from a stalled lag-report stream. ([#6042](https://github.com/rocicorp/mono/pull/6042)) +- [**Immutable query result updates:**](/docs/react#TODO) Query result updates now preserve references for unchanged subtrees, improving compatibility with React memoization and Solid reactivity without the earlier eager-expansion regression. ([#6093](https://github.com/rocicorp/mono/pull/6093)) + +## Performance + +- [Batched flip-join requests, with benchmarks showing large wins for high-cardinality relationship queries.](https://github.com/rocicorp/mono/pull/5928) +- [Avoided O(N²) debug row accumulation in `Debug.rowVended`, reducing overhead for large analyze/debug workloads.](https://github.com/rocicorp/mono/pull/5991) +- [Replaced queue dequeue behavior that could become O(N²) under heavy replication load with an O(1) ring buffer.](https://github.com/rocicorp/mono/pull/5986) +- [Added transaction-scoped copy-on-write for multi-change transactions, reducing allocation overhead and showing roughly 2x wins for large transactions.](https://github.com/rocicorp/mono/pull/6097) + +## Fixes + +- [WebSocket close code `1009` could trap a client in a reconnect loop by repeatedly resending the same oversized message.](https://github.com/rocicorp/mono/pull/5982) +- [Inspector/analyze-query could show a query plan different from the actual plan generated by the table source.](https://github.com/rocicorp/mono/pull/5990) +- [Duplicate bundled copies of runtime peer dependencies could break customer-observable behavior such as `Pool instanceof` checks and React single-instance assumptions.](https://github.com/rocicorp/mono/pull/6046) +- [Singular and plural queries with the same AST could incorrectly share a client view.](https://github.com/rocicorp/mono/pull/6065) +- [Removing a query could trigger an assertion.](https://github.com/rocicorp/mono/pull/6066) +- [`LIKE`/`ILIKE` matching in the JS query engine used multiline regex behavior instead of dotall behavior, causing mismatches for strings containing newlines.](https://github.com/rocicorp/mono/pull/6083) (thanks [@sravan27](https://github.com/sravan27)!) +- [Range filters (`<`, `<=`, `>`, `>=`) could use ordering that differed from SQLite/Postgres ordering.](https://github.com/rocicorp/mono/pull/6088) (thanks [@sravan27](https://github.com/sravan27)!) +- [SQLite replica `LIKE`/`ILIKE` behavior could diverge from Postgres and the in-memory JS matcher.](https://github.com/rocicorp/mono/pull/6095) +- [SQLite replica `ILIKE` did not match non-ASCII case variants such as `MÜLLER` and `müller`.](https://github.com/rocicorp/mono/pull/6098) + +## Breaking Changes + +None confirmed. + +The following query-correctness changes are still under review because they can +change which rows match a query: + +1. SQLite replica `LIKE`/`NOT LIKE` now matches Postgres by being + case-sensitive. Previously, SQLite's default `LIKE` behavior could match + case-insensitively. +1. SQLite replica `ILIKE`/`NOT ILIKE` now compiles as + `lower(left) LIKE lower(right)` instead of reusing bare SQLite `LIKE`. +1. SQLite replica `LIKE`/`ILIKE` now emits `ESCAPE '\'`, so patterns like + `100\%` and `a\_b` treat `%` and `_` literally, matching Postgres and the JS + matcher. +1. SQLite replica `ILIKE` now uses Unicode-aware lowercasing, so non-ASCII case + variants such as `MÜLLER` and `müller` can match. This is not full Unicode + case folding; cases like `straße` and `STRASSE` still do not match. + +We also still need to investigate whether these `LIKE`/`ILIKE` changes affect +SQLite index use or hot-query latency.