Skip to content

升级 Timegrass 到 Calcit 0.22.1 并收窄类型 / Migrate Timegrass to Calcit 0.22.1 and strengthen types - #101

Merged
tiye merged 37 commits into
mainfrom
feat/agent-021-strict-migration
Sep 26, 2026
Merged

tiye merged 37 commits into
mainfrom
feat/agent-021-strict-migration

Conversation

@tiye

@tiye tiye commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

中文

完成 Timegrass 的 Calcit 0.22.1 迁移与数据库类型加强。Fixes #102。关联 calcit-lang/calcit#1306、calcit-lang/calcit#1285、calcit-lang/calcit#1286。

  • 闭合的 DatabaseRecord / SessionRecord / UserRecord / UserTasks / TaskRecord / NoteRecord;Route 枚举和通知记录。所有业务 updater 接收、返回 DatabaseRecord,缺失用户、session 或记录时安全 no-op。
  • 保留旧 Map 持久化格式和客户端投影;启动验证旧数据并转换记录,保存清空 sessions。网络入口兼容旧操作载荷及类型化 EDN 往返,密码不进入公开用户投影。
  • 完成 session 通知删除、typed Dayjs adapter、有限路由解码;修复 Struct 数据库的日期定时更新和 SyncMetrics 读取。使用 Calcit structured edit / surface-latest-v2 完成源码迁移,移除未引用的旧 focus effect。
  • 依赖图严格解析 16 个模块,使用已发布的 Cumulo Reel 0.0.46;Yarn 4.18.0 + node-modules linker。无 js-out/dist/binary 入库,calcit.cirru 不标记 generated。PR 不部署线上页面或服务器。

本地验收

  • 双入口严格检查;14 项 client + 90 项 server definition tests。
  • 双入口零静态 dynamic-method findings、零 deprecated API;全项目 syntax-fix 预览零建议。
  • 不可变 Yarn 安装、caps 严格依赖/工具链验证、JS 生成、Node 24/Vite 生产构建、Dayjs/session-message/typed-database JS 回归全部通过。
  • 独立本地 native server + Browser 验证注册/登录、任务创建/完成、历史路由、笔记新增/编辑、错误通知移除、保存及重启后的自动登录/数据恢复、日期定时更新。没有修改线上存储。

边界说明:仍保留旧存储/投影、UI state 和 ReelState 边界的 Dynamic。formatter 原始 unresolved 统计 55 → 62(新增明确的 legacy adapter/decoder);这不是零债务声明,也没有扩大旧 baseline。数据库/业务 updater 已闭合,未新增 unsafe-coerce;质量门禁为严格检查、定义测试和实际 runtime 回归。详见 迁移与验收记录。

English

Completes the Calcit 0.22.1 migration with closed database, session, user/task/note and route models. Business updaters now use DatabaseRecord throughout and safely ignore stale/missing entities. Explicit adapters preserve legacy Map storage and client projections, validate old data on load, drop transient sessions on save, and keep password fields out of the public user projection.

Includes typed operation/wire decoding, session-message removal, Dayjs adapters, the Struct-safe date timer and sync metrics fix, and whole-project compiler-guided syntax updates. Strict dependency resolution uses released Reel 0.0.46; Yarn 4.18.0 uses node-modules. No generated artifacts are committed and PR events do not deploy.

Local validation: strict client/server checks; 14 client + 90 server definition tests; zero static dynamic-method findings/deprecations; empty full-project syntax-fix preview; immutable install and toolchain verification; Node 24/Vite build; generated-JS regressions. A real browser against isolated native storage verified signup/login, tasks, history, notes, notifications, persistence/restart and the date timer.

Dynamic remains at explicit legacy serialization/projection, UI-state and library boundaries. Raw unresolved-slot counts rose from 55 to 62 with the new adapters; no unsafe coercions or legacy-budget expansion were introduced. Strict checks and native/JS/browser regressions are the reviewed replacement gates. This source migration awaits user review/merge.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

最新 head a4336e4 的 CI 已恢复通过。前一提交收紧 *client-states 后暴露了 Calcit #1343:when 内嵌套 typed get 会生成非法 &let 绑定。当前在消费者侧以显式 let 保持语义并规避,核心缺陷仍需在 Calcit :tests 回归。服务端严格检查从 7 降到 5 个直接失败,质量基线未扩大 Dynamic。

English

Exact-head a4336e4 CI is green. Narrowing *client-states exposed Calcit #1343: nested typed get inside when generates an invalid &let binding. An explicit local let preserves consumer behavior for now; the core defect still needs a Calcit :tests regression. Direct server strict failures fell from 7 to 5 without expanding Dynamic quality debt.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

继续在同一 draft 分支推进历史页迁移(dd3421d):将周边界和日期标签隔离到有类型的 Dayjs FFI adapter,comp-history 改为结构化 Fn schema,并通过 &map:vals/&map:keys 保留分组数据的类型,避免异构键值对列表抹掉类型。comp-history 现通过严格类型检查,其内部 19 处 unsafe-coerce 已清零;新增生成 JS 的周边界 smoke。

验证:calcit test app.comp.navigation 3/3;--compat-types js、Node 24 smoke、Vite release build、格式化和 diff check 通过。全项目严格检查仍有 2 个直接失败(overview 和 notes-page),质量基线仍红(12 项定义级回归,虽然 unsafeCoerce 总数比基线少 20)。本 PR 保持 draft,不会放宽基线或合并。

另外发现链式 .with-week (.with-year ...) 未直接 lowering;拆成本地有类型绑定可运行,编译器缺陷已记录在 calcit-lang/calcit#1353。

English

Continued on the same draft branch (dd3421d): moved week bounds and date labels behind typed Dayjs FFI adapters, gave comp-history a structured Fn schema, and kept grouped values typed with &map:vals/&map:keys instead of heterogeneous map pairs. comp-history now passes strict checking and its 19 internal unsafe-coerce calls are gone. The generated-JS smoke now covers week bounds.

Validation: three navigation Calcit tests, compat JS build, Node 24 smoke, Vite release build, formatting, and diff check pass. Whole-app strict check still has two direct failures (overview and notes-page); the quality baseline remains red with 12 definition-level regressions despite 20 fewer unsafe-coerce occurrences overall. This PR remains draft; the baseline will not be widened or merged in this state.

Nested typed method lowering is tracked in calcit-lang/calcit#1353; a local typed binding keeps this consumer path functional.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

继续在同一 draft 分支推进(1995687):notes 页面按原始 note key 分组,避免异构键值对列表丢失类型;overview 的日期与周数经 DateLabels 适配器读取,两个页面和 comp-task 均改为结构化 Fn schema。页面内 8 处 unsafe-coerce 已移除。对 Option 的两个空值位置保留显式类型补充,其余回调仍由类型推断处理。

当前客户端严格检查:应用改动范围内的直接失败为 0;全入口仍有 3 个级联错误和 14 个阻塞定义,源于旧的服务端消息解码和依赖模块方法调用。app.comp.navigation 的 3 个 Calcit 测试、compat JS 编译、Node 24 Dayjs smoke、Vite 构建与 dynamic-methods 检查通过。质量基线仍红:相对旧基线 unsafeCoerce 降 28,但结构化 schema 里的 Dynamic 槽位增加,暂不修改或放宽基线,也不合并 draft。

English

Continued on the same draft branch (1995687): the notes page groups by original note keys without erasing pair types, overview reads date/week labels through DateLabels, and both pages plus comp-task now use structured Fn schemas. Eight page-level unsafe-coerce calls were removed. Two empty Option sites have explicit type annotations; the other callbacks rely on inference.

The changed app definitions now have zero direct strict failures. The full entry still has three cascaded errors and 14 blocked definitions from legacy message decoding and dependency methods. Three Calcit navigation tests, compat JS generation, Node 24 Dayjs smoke, Vite build, and dynamic-methods analysis pass. The quality baseline remains red: unsafe-coerce is down by 28 overall, while Dynamic slots in structured schemas increased. I am not relaxing the baseline or merging this draft.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

同一 draft 分支继续至 feb8e57:decode-server-message 不再用 3 处未受控 unsafe-coerce,而是验证 Map/List 后对已验证 nominal patch 列表作局部显式类型补充。新增 snapshot 与非 nominal patch 两个 Calcit :tests,该定义 6/6 通过;兼容 JS、Node 24 Dayjs smoke 和 Vite build 通过。依赖升级到 ws-edn.calcit 0.0.32。

严格客户端检查现在 0 个直接失败,仍有 2 个依赖级联错误、14 个阻塞定义:导入的 RetryBackoff trait .reset/.next 未被严格解析,已独立记录为 calcit#1354。质量基线仍红;总 unsafeCoerce 较旧基线少 31,但结构化 schema 的 Dynamic 槽位仍超旧预算。PR 保持 draft,不放宽门禁。

English

Continued on the same draft branch through feb8e57. decode-server-message no longer uses three unchecked unsafe-coerce calls: it validates Map/List input and adds a local explicit type only after validating nominal patch elements. Two Calcit :tests cover snapshots and non-nominal patches; all six tests on this definition pass. Compat JS, Node 24 Dayjs smoke, and Vite build pass. Upgraded ws-edn.calcit to 0.0.32.

The strict client check has zero direct failures but still has two cascaded dependency errors and 14 blocked definitions: imported RetryBackoff trait methods .reset/.next are not resolved, tracked as calcit#1354. The quality baseline is still red; total unsafe-coerce is down 31 from the old baseline, but Dynamic slots in structured schemas exceed its old budget. This PR remains draft and gates are not relaxed.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

同一 draft 分支继续至 0a88a5f:客户端 318 个定义的严格检查已全部通过(0 failed / blocked / cascaded)。把 URL 查询和 navigator 边界声明为最小 external-object trait,浏览器可见性改用 js-ffi 的类型化接口,dispatch 的 console 输出改用现有 typed helper;修正 revision-mismatch 测试中未定型的空 patch 列表。客户端 11/11 个 definition :tests 通过,JS 编译、Node 24 Vite release build 与 Snapshot 格式检查通过。

PR 仍保持 draft:服务端严格检查还有 5 个直接失败、16 个阻塞和 2 个级联;旧质量基线仍有 18 个定义级回退(主要是旧组件的 Dynamic / unresolved),未放宽基线或改测试期望。继续在此分支清理这些门禁。

English

Continued on the same draft branch at 0a88a5f: strict checking now passes all 318 client definitions (0 failed, blocked, or cascaded). Added minimal external-object traits for URL-query and navigator boundaries, used the typed js-ffi visibility API and console helper, and replaced an untyped empty patch list in the revision-mismatch test with a nominal patch. All 11 client definition-attached tests, JS compilation, the Node 24 Vite release build, and Snapshot formatting pass.

The PR remains a draft. Server strict checking still has 5 direct failures, 16 blocked definitions, and 2 cascades; the existing quality baseline reports 18 definition-level regressions, mostly Dynamic/unresolved in older UI components. No baseline was widened and no test expectation was weakened. I will keep resolving these gates on this branch.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

同一 draft 分支继续至 c150fea:服务端 5 个整函数 Dynamic 直接失败已清零。twig 的 map 过滤函数与 updater 使用保持键/值关系的泛型 Fn schema;仅在旧 read-path 返回开放值、进入 typed twig 调用时做局部 decode-map-as。新增登录态隐私投影和 twig-user 的 Calcit :tests。客户端严格检查仍是 318/318 通过;服务端严格检查现为 0 failed、15 blocked、3 cascaded。兼容模式下 29/29 个定义测试、JS 编译和 Vite 构建通过。质量分析的 schemaDynamic 从上一个提交的 76 降至 72,但旧基线的 18 项定义级回退仍未清除,PR 继续保持 draft。

剩余工作包括拆解下游 updater 的整函数 Dynamic、两处 reset! 类型级联、UI 质量基线,并评估投影热路径中局部 decode 的成本;这些完成前不会合并。

English

Continued on the same draft branch at c150fea: all five direct whole-Dynamic server failures are gone. The twig map filters and updater now use generic Fn contracts that preserve key/value relationships; localized decode-map-as calls narrow the legacy open read-path values at typed twig boundaries. Added Calcit definition tests for logged-in privacy projection and twig-user. Client strict checking remains 318/318 green; server strict checking is now 0 failed, 15 blocked, 3 cascaded. All 29 definition tests in compatibility mode, JS compilation, and the Vite build pass. schemaDynamic fell from 76 to 72 versus the prior commit, but the 18 definition-level regressions against the old quality baseline remain. The PR stays a draft.

Remaining work: type downstream updater functions, resolve two reset! type cascades, clear the UI quality baseline, and assess the localized decode cost on the projection hot path. This PR will not be merged until those gates are addressed.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

同一 draft 分支推进至 6c8b049:服务端客户端状态更新不再经 assoc-in/匿名 update 丢失 Ref 类型。新增保留其他客户端状态及缺失客户端行为的纯函数和 Calcit :tests;next-sync-send-state 的泛型契约现明确保留 map 键值类型。对 ReelState.db 的开放值只在进入 typed twig 投影时做显式 map decode。

服务端严格检查现为 0 个直接失败、1 个 updater 依赖级联、6 个阻塞;客户端仍 318/318 通过。兼容模式 33/33 个 Calcit 测试、JS 编译、Vite 构建、Snapshot 格式检查通过。旧 UI 质量基线仍有 18 项定义级回退,PR 保持 draft,不合并。

English

Continued on the same draft branch at 6c8b049: server client-state updates no longer erase Ref types through assoc-in or an anonymous update. Pure helpers and Calcit definition tests preserve other clients' state and the missing-client behavior. The next-sync-send-state generic contract now preserves the map key/value relationship. The open ReelState.db value is explicitly decoded as a map only at the typed twig projection boundary.

Server strict checking is now at 0 direct failures, 1 updater-dependency cascade, and 6 blocked definitions; client strict checking remains 318/318 green. All 33 Calcit tests in compatibility mode, JS compilation, Vite build, and Snapshot formatting pass. The old UI quality baseline still has 18 definition-level regressions, so this PR remains a draft and will not be merged.

@tiye

tiye commented Sep 24, 2026

Copy link
Copy Markdown
Member Author

中文

同一 draft 分支推进到 a227999:将业务操作 Op :today 的 payload 从 Dynamic 收紧为 String,在 decode-operation 的入口用 try-decode-map-as 验证,并在失败时返回 MessageDecodeError。Calcit :tests 覆盖字符串保值、数字及 nil 拒绝;0.20.0 客户端严格检查、客户端 11 项测试、server 测试 36 项、严格 JS 生成和 Node 24/Vite 构建通过。服务端全入口严格检查仍卡在历史 whole-Dynamic updater helper;质量基线仍有 15 项旧回退且未改动。新 HEAD CI 正在运行,PR 保持 draft。

English

The same draft branch is now at a227999. The business operation Op :today carries String instead of Dynamic; decode-operation validates the boundary with try-decode-map-as and returns MessageDecodeError on invalid payloads. Calcit definition tests cover string preservation and rejection of numbers and nil. On Calcit 0.20.0, strict client checking, 11 client tests, 36 server-entry tests, strict JS generation, and the Node 24/Vite build pass. Full strict server checking still reaches legacy whole-Dynamic updater helpers; the quality baseline retains 15 prior regressions and was not changed. CI for this new head is running, and the PR remains draft.

@tiye

tiye commented Sep 26, 2026

Copy link
Copy Markdown
Member Author

中文

推进到 0c4ffe7:CLI、@calcit/procs 和 CI 对齐 0.22.1,Yarn 4.18.0 使用 node-modules linker。仅对本次新发布的精确 runtime 版本设置 age-gate 例外,保留其他默认安全限制。CI 移除重复的兼容模式步骤,保留双入口严格检查和测试。

通过 surface-latest-v2 的 revision-protected fix 简化客户端枚举构造和冗余 do;复查该范围没有剩余建议。工具同时将 core 类型引用规范化为限定名称,已审阅 diff。

本地通过:客户端/服务端严格检查、11 + 79 项 Calcit 测试、JS 生成、Node 24/Vite 生产构建、Dayjs runtime smoke、immutable Yarn install、caps toolchain 校验,以及双入口零静态动态方法发现。未提交编译产物。

仍保持 Draft:#102 的完整数据库模型尚未完成;全项目 fix 仍遇到未引用的旧 effect-focus 无类型契约;Cumulo Reel 0.0.45 仍要求 ws-edn 0.0.31,与应用 0.0.32 存在旧依赖约束告警。后续先发布已合并的 Reel 修复,再推进数据库和剩余源码迁移。未改线上部署路径,PR 不执行部署。

English

Updated to 0c4ffe7: CLI, @calcit/procs, and CI now use 0.22.1, with Yarn 4.18.0 and the node-modules linker. Only the exact newly published runtime gets an age-gate exception; other security defaults remain enabled. CI retains strict checks/tests for both entries and removes redundant compatibility-mode steps.

Applied revision-protected surface-latest-v2 fixes to client enum constructors and redundant do forms; the scoped follow-up preview is empty. Reviewed the tool's normalization of qualified core type references too.

Local validation passed: both strict entry checks, 11 client + 79 server Calcit tests, JS generation, Node 24/Vite production build, Dayjs runtime smoke, immutable Yarn install, caps toolchain verification, and zero static dynamic-method findings for both entries. No generated artifacts are committed.

This remains a Draft: the complete database model in #102 is unfinished, whole-project fix encounters an unreferenced legacy effect-focus without a typed contract, and Reel 0.0.45 still requests ws-edn 0.0.31 while the app uses 0.0.32. Next: release the merged Reel fix, then continue database/source migration. Production deployment paths are unchanged; PRs do not deploy.

@tiye tiye changed the title 升级 Timegrass 到 Calcit 0.20 并阶段性收窄 FFI / Stage Timegrass Calcit 0.20 migration and narrow FFI 升级 Timegrass 到 Calcit 0.22.1 并收窄类型 / Migrate Timegrass to Calcit 0.22.1 and strengthen types Sep 26, 2026
@tiye

tiye commented Sep 26, 2026

Copy link
Copy Markdown
Member Author

中文

已发布上游 Cumulo Reel 0.0.46,发布提交 9685e12 的 主分支 Actions 成功。

本 PR 更新至 7546f3c:使用 Reel 0.0.46,并将 CI 安装改为 caps --strict --ci。此前 ws-edn 0.0.31/0.0.32 的约束冲突已消除,16 个模块严格解析及 toolchain 校验通过。本地双入口严格检查、11 + 79 项测试、immutable Yarn install、JS/Vite 构建和 Dayjs smoke 均通过。没有提交编译产物,也没有触发部署。

仍保持 Draft,下一步继续 #102 的数据库/session/updater 类型收紧;依赖冲突不再是阻塞项。

English

Published upstream Cumulo Reel 0.0.46 after successful main CI for release commit 9685e12.

This PR advances to 7546f3c: consumes Reel 0.0.46 and enforces caps --strict --ci. The ws-edn 0.0.31/0.0.32 constraint conflict is resolved; all 16 modules pass strict resolution and toolchain verification. Local strict checks for both entries, 11 + 79 tests, immutable Yarn install, JS/Vite build, and Dayjs smoke pass. No generated artifacts are committed or deployment triggered.

Still a Draft; next is the database/session/updater typing work in #102. The dependency conflict is no longer a blocker.

@tiye

tiye commented Sep 26, 2026

Copy link
Copy Markdown
Member Author

中文

5dd9ec7 收紧 session 通知删除边界:内部操作和 updater 的 ID 从 Dynamic 改为 String。解码器兼容旧客户端 {:id String} Map,也接受新的字符串 ID;缺失、nil、数字 ID 返回错误。UI 回调先解码再 dispatch。迟到操作遇到已断开的 session 时保持数据库不变,不再重建空 session。

新增 Calcit tests 覆盖新旧输入、序列化往返、非法 ID、目标消息隔离、重复删除与缺失 session;新增生成 JS 的解码/updater smoke 并接入 CI。本地客户端 13 项、服务端 83 项测试、双入口严格检查、JS/Vite 构建、Dayjs smoke、immutable Yarn install 均通过;双入口静态动态方法报告均为零。未增加 unsafe-coerce,未提交编译产物。

这是 #102 的小步推进,不是完整 session/database Struct 迁移;PR 继续 Draft。下一步仍需明确 router/message/session 模型,再连接数据库根和 updater。

English

5dd9ec7 narrows session-message removal from Dynamic to a String ID in the operation and updater. Boundary decoding accepts both legacy {:id String} maps and new string IDs, rejects missing/nil/numeric IDs, and validates the UI callback before dispatch. Late operations against disconnected sessions are now no-ops instead of recreating empty sessions.

Added Calcit tests for both wire shapes, serialization round-trips, malformed IDs, message/session isolation, repeated removal, and missing sessions. Added generated-JS decoder/updater regression checks to CI. Local validation passes: 13 client tests, 83 server tests, both strict entry checks, JS/Vite build, Dayjs smoke, immutable Yarn install, and zero static dynamic-method findings. No new unsafe coercions or generated artifacts.

This is an incremental step for #102, not the complete session/database Struct migration. The PR remains Draft; router/message/session modeling and the typed database/updater integration remain outstanding.

@tiye
tiye marked this pull request as ready for review September 26, 2026 07:23
@tiye

tiye commented Sep 26, 2026

Copy link
Copy Markdown
Member Author

Completed at b54d25782943c41f672361de975d8cd53533a5de and marked Ready for Review.

  • Closed DatabaseRecord/session/user/task/note/route models now drive all business updaters; legacy persistence and client projections remain explicit boundary adapters.
  • Local strict checks, 14 client + 90 server tests, generated-JS regressions, full syntax-fix preview, dependency/toolchain validation and Node 24 production build pass.
  • Real isolated browser/native-server smoke passed signup/login, task completion/history, note creation/editing, notification removal, persistence/restart recovery and the date timer. This caught and fixed a stale Map access on the typed database.
  • Exact-head Actions passed; no unresolved review threads at this check. No generated artifacts or production data changes.

The PR body and docs/typed-database.md now replace the old incremental Draft status with current acceptance evidence and explicitly document remaining legacy-boundary Dynamic usage. Source changes are not merged; awaiting owner review. #102 closes on merge.

@tiye
tiye merged commit e78e0d0 into main Sep 26, 2026
1 check passed
@tiye
tiye deleted the feat/agent-021-strict-migration branch September 26, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

为异构数据库建立真实类型契约 / Model the heterogeneous database with sound types

1 participant