diff --git a/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.md b/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.md index 8c873d0e5a..3dced8df43 100644 --- a/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.md +++ b/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.md @@ -125,6 +125,38 @@ consumer chain, including a committed-but-lost native reply. Its discovered rese fall-through is a renderer recovery defect; no further native write change is required by that correction. +## SQLite namespace diagnostics + +The streaming-budget test inspects a temporary Native SQLite database directly. +Its three statistics queries must support both the installed container v3 +(`roost_kv.space`) and container v4's interned namespaces (`roost_spaces.name` +joined by `space_id`). A test-local relation exposes the same `space/key/value` +columns for either format, with an explicit accepted-version assertion. Update +bytes, receipt count and projection-row budgets remain unchanged. The diagnostic +relation changes no production read/write behavior. Companion storage work: +[Roost #15](https://github.com/loro-dev/roost/pull/15). +Diagnostic compatibility PR: [#1735](https://github.com/LodyAI/Lody/pull/1735). + +The coordinated Roost 0.2.0 release is now published. PR #1735 pins the +TypeScript package in the shared catalog and Native exactly in the CLI manifest +and publication guard, retaining the published-runtime version contract. It keeps all six exact +platform dependencies in the lockfile and release-age exceptions. This upgrades +the Native runtime to SQLite container v4; earlier containers are refused, with +no migration, automatic reset or data cleanup. The dependent +[message-state fix #1737](https://github.com/LodyAI/Lody/pull/1737) consumes this +same catalog update and must merge after #1735. Acceptance is repeated against +the published packages rather than a local SDK artifact. + +Frozen installation, complete `pnpm check`, repository format and documentation +checks pass with the published 0.2.0 packages and no native override. The full CLI +suite passes 4,429 tests with four existing skips, including streaming storage +budgets and reopen. The four Electron native-staging tests pass: foreign target +selection uses synthetic bindings; the installed host binding executes real +signed SQLite write/reopen probes. The Native release manifest identifies merged +Roost source `e85c970`; this is not cross-platform runtime acceptance on this host. +The public CLI build also passes at a 2 GiB heap, including its published-bundle +runtime probes; all six existing dependency-version policy tests pass. + ## Outbox and existing data Outbox rows are not pending-delivery counts. The installed TypeScript Store's ACK diff --git a/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.zh.md b/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.zh.md index 3bd9bccb67..c2de357dee 100644 --- a/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.zh.md +++ b/.agents/notes/implemented/bug-fix/2026-10-16-roost-storage-write-amplification.zh.md @@ -103,6 +103,30 @@ Native 写入与其他客户端的增量正文读取,不足以作为发行验 把生产 RPC 加解密端点和两个渲染器副本加入同一消费者链路,并覆盖原生提交成功但回复丢失。 其中发现的 reset 快捷路径是渲染器恢复缺陷;这项更正不需要继续修改原生写入。 +## SQLite namespace 统计 + +流式预算测试直接检查临时 Native SQLite 数据库。三处统计查询同时支持当前安装的 +container v3(`roost_kv.space`)和 namespace 整数引用的 v4(通过 `space_id` +关联 `roost_spaces.name`)。测试内的查询关系为两种格式提供相同的 +`space/key/value` 列,并显式断言支持的版本;更新字节、回执行数和投影行数预算不变。 +统计查询本身不改变生产读写行为。 +配套存储改动:[Roost #15](https://github.com/loro-dev/roost/pull/15)。 +统计兼容 PR:[#1735](https://github.com/LodyAI/Lody/pull/1735)。 + +Roost 0.2.0 已统一发布。PR #1735 在共享 catalog 固定 TypeScript 包,在 CLI +清单及发布校验中精确固定 Native,沿用运行时依赖发布合同。锁文件及发布冷却期 +豁免保留全部六个精确匹配的平台包。Native 运行时 +因此升级到 SQLite container v4,拒绝更早容器,不迁移、不自动重置、不清理数据。 +依赖它的[消息状态修复 #1737](https://github.com/LodyAI/Lody/pull/1737) 复用同一次 +catalog 更新,在 #1735 后合并。验收改用 npm 正式包,不再使用本地 SDK 产物。 + +使用 npm 正式 0.2.0 包、没有 Native 覆盖时,冻结安装、完整 `pnpm check`、 +全仓格式和文档检查通过。CLI 全量 4,429 项通过、4 项原有跳过,包含流式存储预算 +及重开。Electron 四项 Native staging 测试通过:其他平台使用合成绑定验证选择, +本机安装的真实绑定执行签名 SQLite 写入及重开。Native 发布 manifest 对应已合并的 +Roost 源码 `e85c970`;这不代表在本机完成其他平台的运行时验收。 +公开 CLI 在 2 GiB 堆上限内构建通过,包含发布包运行时探针;六项已有依赖版本策略测试通过。 + ## Outbox 与既有数据 Outbox 行数不等于待发送数量。已安装 TypeScript Store 的 ACK 推进消费者游标而不删除行, diff --git a/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.md b/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.md index 953e3c311a..de2d7245dc 100644 --- a/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.md +++ b/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.md @@ -21,11 +21,12 @@ history coverage and device-level responsiveness remain validation limits. ## Decision and boundaries -Pin `@loro-dev/roost-node@0.1.2` as a CLI runtime dependency and exempt only that -version and its six exact platform dependencies from the release-age policy. -Keep `@loro-dev/roost@0.1.2` for identity, -application JSON, and `NodeLodyHistory`. Neither Rust source nor a sibling Roost -checkout is needed to install, build, or package Lody. +Pin `@loro-dev/roost-node@0.2.0` as an exact CLI runtime dependency, with +`@loro-dev/roost@0.2.0` from the shared catalog for identity, application JSON, and +`NodeLodyHistory`. Exempt only these exact versions and the six matching platform +dependencies from the release-age policy. Native 0.2.0 uses SQLite container v4; +it refuses earlier containers without migration or automatic reset. Neither Rust +source nor a sibling Roost checkout is needed to install, build, or package Lody. Use `RoostNativeClient` directly. Preserve the database path, credential-store seed, admitted owner, bounded queue, shared stream leases, and awaited final close. diff --git a/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.zh.md b/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.zh.md index 2c621cd4d5..167e654c9c 100644 --- a/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.zh.md +++ b/.agents/notes/proposed/architecture/2026-10-09-roost-native-runtime.zh.md @@ -17,9 +17,10 @@ CLI 现在接入已发布的 Node-API 包,在 Worker 内运行 SQLite 实现 ## 决策与边界 -CLI 运行依赖固定为 `@loro-dev/roost-node@0.1.2`,发布冷却期仅豁免该版本及 -六个精确匹配的平台包版本。 -保留 `@loro-dev/roost@0.1.2` 的身份、应用 JSON 和 `NodeLodyHistory` 适配器。 +CLI 将运行依赖精确固定为 `@loro-dev/roost-node@0.2.0`,身份、应用 JSON 和 +`NodeLodyHistory` 使用共享 catalog 的 `@loro-dev/roost@0.2.0`。 +发布冷却期仅豁免这两个精确版本和六个匹配的平台包版本。 +Native 0.2.0 使用 SQLite container v4,拒绝更早容器,不迁移或自动重置。 安装、构建和打包 Lody 无须 Rust 源码或旁边的 Roost 仓库。 直接使用 `RoostNativeClient`,保留数据库位置、系统凭据存储中的种子、允许的签名身份、 diff --git a/apps/cli/package.json b/apps/cli/package.json index 9d88d95b44..3d2607ae0a 100644 --- a/apps/cli/package.json +++ b/apps/cli/package.json @@ -55,7 +55,7 @@ "@lody/shared": "workspace:*", "@lody/turn-diff-store": "workspace:*", "@loro-dev/flock-wasm": "catalog:", - "@loro-dev/roost": "0.1.3", + "@loro-dev/roost": "catalog:", "@loro-dev/streams-crdt": "catalog:", "@loro-dev/streams-client": "catalog:", "@modelcontextprotocol/client": "2.0.0", @@ -128,7 +128,7 @@ ], "dependencies": { "@effect/platform-node-shared": "catalog:", - "@loro-dev/roost-node": "0.1.2", + "@loro-dev/roost-node": "0.2.0", "@lydell/node-pty": "1.2.0-beta.14", "@napi-rs/keyring": "2.1.0", "better-sqlite3": "catalog:", diff --git a/apps/cli/scripts/check-published-bundle-imports.js b/apps/cli/scripts/check-published-bundle-imports.js index e525a41cac..cb0d761848 100644 --- a/apps/cli/scripts/check-published-bundle-imports.js +++ b/apps/cli/scripts/check-published-bundle-imports.js @@ -41,7 +41,7 @@ const requiredPublishedRuntimeDependencies = [ const requiredExactPublishedRuntimeDependencies = ['loro-crdt']; const requiredPinnedPublishedRuntimeDependencies = new Map([ ['@lydell/node-pty', '1.2.0-beta.14'], - ['@loro-dev/roost-node', '0.1.2'], + ['@loro-dev/roost-node', '0.2.0'], ]); for (const block of dependencyBlocks) { diff --git a/apps/cli/tests/roost-session-backend-contract.test.ts b/apps/cli/tests/roost-session-backend-contract.test.ts index 15f8f4b214..95ba3d9344 100644 --- a/apps/cli/tests/roost-session-backend-contract.test.ts +++ b/apps/cli/tests/roost-session-backend-contract.test.ts @@ -2516,18 +2516,25 @@ describe('Production Roost history semantics', () => { } const db = new Database(join(nativeDirectory, 'history.db'), { readonly: true }); try { + const containerVersion = db.pragma('user_version', { simple: true }); + expect([3, 4]).toContain(containerVersion); + const kvRows = + containerVersion === 4 + ? `(SELECT roost_spaces.name AS space, key, value + FROM roost_kv JOIN roost_spaces ON roost_spaces.id = roost_kv.space_id)` + : 'roost_kv'; const stats = db .prepare(`SELECT COUNT(*) AS rows, SUM(LENGTH(key) + LENGTH(value)) AS bytes - FROM roost_kv WHERE space LIKE ?`) + FROM ${kvRows} WHERE space LIKE ?`) .get(`%${fixture.doc.sessionId}%:updates`) as { rows: number; bytes: number }; expect(stats.rows).toBeGreaterThan(128); expect(stats.bytes).toBeLessThan(1024 * 1024); const receipts = db - .prepare(`SELECT COUNT(*) AS count FROM roost_kv WHERE space LIKE ?`) + .prepare(`SELECT COUNT(*) AS count FROM ${kvRows} WHERE space LIKE ?`) .get(`%${fixture.doc.sessionId}%:lody_agent_operation_receipts_v1`) as { count: number }; expect(receipts.count).toBe(128); const projection = db - .prepare(`SELECT COUNT(*) AS count FROM roost_kv WHERE space LIKE ?`) + .prepare(`SELECT COUNT(*) AS count FROM ${kvRows} WHERE space LIKE ?`) .get(`%${fixture.doc.sessionId}%:projection`) as { count: number }; expect(projection.count).toBeGreaterThan(0); expect(projection.count).toBeLessThan(1000); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 676d35287d..638c366057 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -63,6 +63,9 @@ catalogs: '@loro-dev/loro-cli': specifier: 0.6.0 version: 0.6.0 + '@loro-dev/roost': + specifier: 0.2.0 + version: 0.2.0 '@loro-dev/streams-client': specifier: 0.12.1 version: 0.12.1 @@ -260,8 +263,8 @@ importers: specifier: 'catalog:' version: 4.0.2(effect@4.0.2) '@loro-dev/roost-node': - specifier: 0.1.2 - version: 0.1.2 + specifier: 0.2.0 + version: 0.2.0 '@lydell/node-pty': specifier: 1.2.0-beta.14 version: 1.2.0-beta.14 @@ -321,8 +324,8 @@ importers: specifier: 'catalog:' version: 0.4.4 '@loro-dev/roost': - specifier: 0.1.3 - version: 0.1.3 + specifier: 'catalog:' + version: 0.2.0 '@loro-dev/streams-client': specifier: 'catalog:' version: 0.12.1(effect@4.0.2) @@ -3857,50 +3860,50 @@ packages: engines: {node: '>=22'} hasBin: true - '@loro-dev/roost-node-darwin-arm64@0.1.2': - resolution: {integrity: sha512-DcbHhL7jTm7itxxBpLoSf14836OH9q9tZz+UZClS0Dy3wf/qZvhaItlZXOu4f4aXBlcOvs/3oA3MS0y52vYnbA==} + '@loro-dev/roost-node-darwin-arm64@0.2.0': + resolution: {integrity: sha512-7Y85fxFS/yS+cXhaRfazCNh76MDp/FDGfbO8pIDNB0Az2D0DITzBHO495FTUkniCLJSyd6tjFhR+qmzBLEweGQ==} engines: {node: '>=22.14.0'} cpu: [arm64] os: [darwin] - '@loro-dev/roost-node-darwin-x64@0.1.2': - resolution: {integrity: sha512-e2aoEBomOPmJrGAedRJRQsEiZGhMq/z8nkPsrl25JM51YCrFynVkXw3Zqb27svyMsbYPsiPJuGE6hpDOStcjyQ==} + '@loro-dev/roost-node-darwin-x64@0.2.0': + resolution: {integrity: sha512-cU/GILiSEto9gO4WR2aOABoqwG11+s/AWStjZ/PwteSrhR+81WLn4ZSlrXW0gtK8Tvu3KOFzuBC3m+LE3eyiGQ==} engines: {node: '>=22.14.0'} cpu: [x64] os: [darwin] - '@loro-dev/roost-node-linux-arm64-gnu@0.1.2': - resolution: {integrity: sha512-lzk+HzP9GouzvGv5eyIaqHxfiafj9Xc+8+9prSXTTK3y3imWzC1esPNyyfkdKszhRlkPeTSansl26Vs6TmZeNQ==} + '@loro-dev/roost-node-linux-arm64-gnu@0.2.0': + resolution: {integrity: sha512-rG4/fK3UlrJQtWz6aAJ7kUWUN/8iDz7RScgqYhtMgp4LjyTnu+HJ8r9Nh1yLGBQOSCv+qMG89nYdK6R0PVWSZQ==} engines: {node: '>=22.14.0'} cpu: [arm64] os: [linux] libc: [glibc] - '@loro-dev/roost-node-linux-x64-gnu@0.1.2': - resolution: {integrity: sha512-2sMZDy1dolPJnDIyr//1SIvcvmPt/Frkdth9+fcmCRY0wQmyeOyXnQTVWAFGRHeYCIuFGB7Vqn4oMb05sRwV0w==} + '@loro-dev/roost-node-linux-x64-gnu@0.2.0': + resolution: {integrity: sha512-htuaQOBfs1qMdJZ7uK2d1Rm7zVNrsFmO6oQj/u70cu1ZWl10Hn6fe4NaiviNvQPcap4CEEdoY3grySvQaDwzpg==} engines: {node: '>=22.14.0'} cpu: [x64] os: [linux] libc: [glibc] - '@loro-dev/roost-node-win32-arm64-msvc@0.1.2': - resolution: {integrity: sha512-muMxGHitya4DGKbuM9gH4UWY/AIeFc3InZgYC0nBiNliVltaBcxUUc177PumvU1Ft+AajsyHEHz27fmAUYjm9A==} + '@loro-dev/roost-node-win32-arm64-msvc@0.2.0': + resolution: {integrity: sha512-phsf9p+53sx8Z5ERkf4iZnQEZs3hWRkXkxsMx07IPyydvSdHxW8LEkQHFPTtNw4q0G7EM5uZuEqlAWAbQrf74A==} engines: {node: '>=22.14.0'} cpu: [arm64] os: [win32] - '@loro-dev/roost-node-win32-x64-msvc@0.1.2': - resolution: {integrity: sha512-ZBVS2oYXaZufO7pxQgIX5iXkthlhJe44Xer6taFC1wgFpcfhgtT90yif+tnFum6T3x6SlF8pzqLR3xQSd/vYiw==} + '@loro-dev/roost-node-win32-x64-msvc@0.2.0': + resolution: {integrity: sha512-cDpciAjAWHoALXiZLTmK/XwS0cpkJ6//bLV7XZ6FXqNuZYzm+wFxl7eiYEG6wS3++g5wRB1qBo6MgLXdbZyt2Q==} engines: {node: '>=22.14.0'} cpu: [x64] os: [win32] - '@loro-dev/roost-node@0.1.2': - resolution: {integrity: sha512-A8RiMXtmjfiI2qNzJ7AhAMsft/am9phNiXVnhnOqy4V9/oFzEYTvsAfoXua0cqq5UhaXP4Xy2R6j+QSb6Z7dtA==} + '@loro-dev/roost-node@0.2.0': + resolution: {integrity: sha512-+3rUDTutVxsouuQmySgM0AZUmPYiVUzlF2vT1vEJeI5QCZQhxNvSPLpe1faXpm+iFN8a6eCl/NUpO/ERdLteRA==} engines: {node: '>=22.14.0'} - '@loro-dev/roost@0.1.3': - resolution: {integrity: sha512-OAXB26dAZ7w80YlKoqHFotQ07nYnWrtW0M915cIyi7LUf7UICQ4lc2ZGBlbrydmuqtyNNXtTzW0hOpHu3fBrNQ==} + '@loro-dev/roost@0.2.0': + resolution: {integrity: sha512-nfWj8wk7q5ZbHCWPqCqptaA6QgYkdcf46JB7M4x2OkpC2gAYDJ8pdwWTMsGpGYPNyCsNqjxhU3T7seQyXe1S4w==} '@loro-dev/streams-client@0.10.0': resolution: {integrity: sha512-FWyrr7AnhJZXsrxubqjjgabD1aRksziU8HNR3WiJoYaPQEX0kDwiqqAJ53xgYI7MurQNfUcGVmSw0aD+TCNSMA==} @@ -16602,34 +16605,34 @@ snapshots: js-yaml: 4.1.1 loro-crdt: 1.16.3 - '@loro-dev/roost-node-darwin-arm64@0.1.2': + '@loro-dev/roost-node-darwin-arm64@0.2.0': optional: true - '@loro-dev/roost-node-darwin-x64@0.1.2': + '@loro-dev/roost-node-darwin-x64@0.2.0': optional: true - '@loro-dev/roost-node-linux-arm64-gnu@0.1.2': + '@loro-dev/roost-node-linux-arm64-gnu@0.2.0': optional: true - '@loro-dev/roost-node-linux-x64-gnu@0.1.2': + '@loro-dev/roost-node-linux-x64-gnu@0.2.0': optional: true - '@loro-dev/roost-node-win32-arm64-msvc@0.1.2': + '@loro-dev/roost-node-win32-arm64-msvc@0.2.0': optional: true - '@loro-dev/roost-node-win32-x64-msvc@0.1.2': + '@loro-dev/roost-node-win32-x64-msvc@0.2.0': optional: true - '@loro-dev/roost-node@0.1.2': + '@loro-dev/roost-node@0.2.0': optionalDependencies: - '@loro-dev/roost-node-darwin-arm64': 0.1.2 - '@loro-dev/roost-node-darwin-x64': 0.1.2 - '@loro-dev/roost-node-linux-arm64-gnu': 0.1.2 - '@loro-dev/roost-node-linux-x64-gnu': 0.1.2 - '@loro-dev/roost-node-win32-arm64-msvc': 0.1.2 - '@loro-dev/roost-node-win32-x64-msvc': 0.1.2 + '@loro-dev/roost-node-darwin-arm64': 0.2.0 + '@loro-dev/roost-node-darwin-x64': 0.2.0 + '@loro-dev/roost-node-linux-arm64-gnu': 0.2.0 + '@loro-dev/roost-node-linux-x64-gnu': 0.2.0 + '@loro-dev/roost-node-win32-arm64-msvc': 0.2.0 + '@loro-dev/roost-node-win32-x64-msvc': 0.2.0 - '@loro-dev/roost@0.1.3': + '@loro-dev/roost@0.2.0': dependencies: '@loro-dev/streams-client': 0.8.0 '@noble/curves': 2.4.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 1a057fb22c..90c7196f7e 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -28,6 +28,7 @@ catalog: '@devframes/plugin-terminals--assets': 1.0.0 '@loro-dev/flock-wasm': ^0.4.4 '@loro-dev/loro-cli': 0.6.0 + '@loro-dev/roost': 0.2.0 '@loro-dev/sqlite-riverrun': 0.2.0 '@loro-dev/streams-client': 0.12.1 '@loro-dev/streams-crdt': 0.19.1 @@ -87,15 +88,15 @@ minimumReleaseAgeExclude: - '@effect/vitest@4.0.2' - '@effect/platform-node-shared@4.0.2' # Keep the split release's complete optional platform graph available on every host. - - '@loro-dev/roost-node@0.1.2' - - '@loro-dev/roost-node-darwin-arm64@0.1.2' - - '@loro-dev/roost-node-darwin-x64@0.1.2' - - '@loro-dev/roost-node-linux-arm64-gnu@0.1.2' - - '@loro-dev/roost-node-linux-x64-gnu@0.1.2' - - '@loro-dev/roost-node-win32-arm64-msvc@0.1.2' - - '@loro-dev/roost-node-win32-x64-msvc@0.1.2' + - '@loro-dev/roost-node@0.2.0' + - '@loro-dev/roost-node-darwin-arm64@0.2.0' + - '@loro-dev/roost-node-darwin-x64@0.2.0' + - '@loro-dev/roost-node-linux-arm64-gnu@0.2.0' + - '@loro-dev/roost-node-linux-x64-gnu@0.2.0' + - '@loro-dev/roost-node-win32-arm64-msvc@0.2.0' + - '@loro-dev/roost-node-win32-x64-msvc@0.2.0' # Use the pinned npm release instead of requiring a sibling Roost checkout. - - '@loro-dev/roost@0.1.3' + - '@loro-dev/roost@0.2.0' # pnpm 10.20 uses the first rule per package; keep exact Codex versions together. - '@openai/codex@0.154.0 || 0.156.0 || 0.156.0-darwin-arm64 || 0.156.0-darwin-x64 || 0.156.0-linux-arm64 || 0.156.0-linux-x64 || 0.156.0-win32-arm64 || 0.156.0-win32-x64 || 0.159.2 || 0.159.2-darwin-arm64 || 0.159.2-darwin-x64 || 0.159.2-linux-arm64 || 0.159.2-linux-x64 || 0.159.2-win32-arm64 || 0.159.2-win32-x64' # Exact transitive dependencies already selected for werift.