@calcit/procs 0.11.8 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/.gitattributes +1 -1
  2. package/.yarn/install-state.gz +0 -0
  3. package/build.rs +229 -11
  4. package/editing-history/2026-0305-0042-type-inference-argtypes-and-core-hints.md +54 -0
  5. package/editing-history/2026-0305-0115-calcit-core-generic-refinements.md +57 -0
  6. package/editing-history/2026-0305-1930-schema-migration-cr-edit.md +30 -0
  7. package/editing-history/2026-0305-1939-query-schema-adaptation.md +42 -0
  8. package/editing-history/2026-0306-0120-schema-hint-migration-batch.md +38 -0
  9. package/editing-history/2026-0306-1416-core-macro-schema-migration.md +20 -0
  10. package/editing-history/2026-0306-1552-core-schema-and-hintfn-migration.md +63 -0
  11. package/editing-history/2026-0306-1936-schema-normalization-and-preprocess-preload.md +12 -0
  12. package/editing-history/2026-0307-0000-migrate-hint-fn-to-schema.md +29 -0
  13. package/editing-history/2026-0307-0000-remove-enum-prototype-field.md +43 -0
  14. package/editing-history/2026-0307-0000-schema-args-type-enforcement.md +66 -0
  15. package/editing-history/2026-0307-0142-unit-type-and-builtin-schemas.md +82 -0
  16. package/editing-history/2026-0307-1302-calcit-agent-docs-update.md +32 -0
  17. package/editing-history/2026-0307-1652-decouple-snapshot-schema-to-calcit-type.md +112 -0
  18. package/editing-history/2026-0307-1821-snapshot-schema-validation.md +6 -0
  19. package/editing-history/2026-0307-1959-schema-def-kind-arity-validation.md +96 -0
  20. package/editing-history/2026-0308-0031-schema-generics-quote-normalization.md +35 -0
  21. package/editing-history/2026-0308-1905-schema-typeref-and-assert-migration.md +34 -0
  22. package/editing-history/2026-0308-2033-schema-wrapper-migration.md +45 -0
  23. package/editing-history/2026-0308-2315-late-schema-cleanup-and-warning-compat.md +27 -0
  24. package/editing-history/2026-0310-1040-edit-schema-primitive-tag-support.md +42 -0
  25. package/editing-history/202603091753-schema-type-fail-tests.md +17 -0
  26. package/editing-history/202603091819-add-test-fail-script.md +5 -0
  27. package/editing-history/202603091944-split-type-fail-tests.md +8 -0
  28. package/lib/package.json +3 -2
  29. package/package.json +3 -2
  30. /package/editing-history/{2026-0304-generics-fn-typevar-identity.md → 2026-0304-0000-generics-fn-typevar-identity.md} +0 -0
@@ -0,0 +1,43 @@
1
+ # 2026-0307 移除 CalcitEnum 的 prototype 字段
2
+
3
+ ## 背景
4
+
5
+ 老版本的 `CalcitEnum` 使用 `prototype: Arc<CalcitRecord>` 存储枚举定义(字段=variant tag,值=payload 类型列表),因为当时 enum 借助 record 的数据结构来定义。现在 enum 已有独立的定义语法(`defenum`),prototype 字段冗余,予以移除。
6
+
7
+ ## 主要变更
8
+
9
+ ### `src/calcit/sum_type.rs`
10
+
11
+ - `CalcitEnum` 结构体:`prototype: Arc<CalcitRecord>` → `name: EdnTag`
12
+ - `from_record` / `from_arc`:提取 name,不再存储整个 record
13
+ - 删除 `prototype()` 方法,新增 `name()` 返回 `&EdnTag`
14
+ - 新增 `to_record_prototype() -> CalcitRecord`:根据 `name + variants` 按需重建 `CalcitRecord`,供 `preprocess.rs` 向后兼容使用
15
+
16
+ ### `src/calcit.rs`
17
+
18
+ - `Hash` 实现:改为对 variant tag + payload type 逐项哈希
19
+ - `PartialEq` 实现:`a.prototype() == b.prototype()` → `a.name() == b.name() && a.variants() == b.variants()`
20
+
21
+ ### `src/calcit/compare.rs`
22
+
23
+ - `compare_calcit_enum_values`:不再对比 prototype record,改为先比较 name,再逐 variant 比较 tag 和 payload types(深度比较),确保 `Ord::cmp == Equal` ⟺ `PartialEq::eq == true`
24
+
25
+ ### `src/data.rs`
26
+
27
+ - `Enum(enum_def)` 序列化分支:通过 `enum_def.name()` 和 `enum_def.variants()` 直接读取,不再依赖 prototype record
28
+
29
+ ### `src/runner/preprocess.rs`
30
+
31
+ - `resolve_record_value` 中所有 `Calcit::Enum(enum_def)` 分支:`enum_def.prototype().to_owned()` → `enum_def.to_record_prototype()`
32
+
33
+ ## 验证结果
34
+
35
+ - `cargo build` ✅(无警告)
36
+ - `cargo test` ✅(94 + 17 = 111 通过,0 失败)
37
+ - `cargo clippy -- -D warnings` ✅(无警告)
38
+ - `yarn check-all` ✅(exit 0)
39
+
40
+ ## 踩坑与注意
41
+
42
+ - `compare_calcit_enum_values` 最初只比 tag 未比 payload types,导致 `cmp_equal_matches_eq_for_complex_named_variants` 失败。修复时需对每个 variant 的 payload types 也做深度比较。
43
+ - `to_record_prototype()` 是按需重建而非缓存,性能上无问题(仅在类型检查预处理阶段调用)。
@@ -0,0 +1,66 @@
1
+ # 2026-03-07 schema.args 类型检查接通与 fn 类型注解修复
2
+
3
+ ## 背景
4
+
5
+ 上一次 session(commit a008f8b)为 calcit-core 的 54+ 函数添加了 `:schema` 中的 `:args` 字段。但发现这些 schema
6
+ 并未实际触发调用现场的类型检查——`CalcitFn.arg_types` 只从函数体的 `assert-type` 扫描,从未读取 schema `:args`。
7
+
8
+ ## 根因分析
9
+
10
+ 类型检查数据流:
11
+
12
+ ```
13
+ calcit-core.cirru :schema :args
14
+ → preprocess.rs 注入为 (HintFn schema_value) 进 defn 体
15
+ → syntax.rs defn 调用 detect_arg_type_hints → collect_arg_type_hints_from_body
16
+ → 只扫描 assert-type/assert-traits,忽略 HintFn!
17
+ → CalcitFn.arg_types 对 schema-only 函数全为 Dynamic
18
+ → check_user_fn_arg_types 提前返回,无任何检查
19
+ ```
20
+
21
+ ## 修复内容
22
+
23
+ ### 1. 接通 schema.args → CalcitFn.arg_types(`syntax.rs` + `type_annotation.rs`)
24
+
25
+ - 新增 `CalcitTypeAnnotation::extract_arg_types_from_hint_form(form, params)` 方法
26
+ - 新增 `parse_schema_args_types` 和 `is_args_list_head` 辅助方法
27
+ - `syntax.rs:defn` 中优先从 hint-fn(schema 注入)提取 arg_types,再回退到 assert-type 扫描
28
+
29
+ ### 2. fn 类型注解解析修复(`type_annotation.rs`)
30
+
31
+ 发现 `(:: :fn ([] 'T 'U) (:: 'T 'U) 'T)` 格式的 fn 类型注解被错误解析,因为 `[]` 头部(list constructor proc)
32
+ 出现在 args 列表中被当作普通类型处理:
33
+
34
+ - **三处** `parse_type_annotation_form` `:fn` 分支:args_form 为 List 时跳过 `[]` 头部
35
+ - **`parse_generics_list`**:跳过 `[]` 头部,使 `([] 'T 'U)` 作为合法 generics 列表(`'T 'U` 不能作 Cirru EDN operator)
36
+ - **`matches_signature`**:移除 generics 数量检查,改用 `matches_with_bindings` 解析 TypeVar 绑定(使具体函数类型能匹配泛型签名)
37
+ - **`matches_with_bindings`**:`Tag` 可满足 `DynFn`/`Fn` 约束(Calcit 中 `:tag` 作为 map key accessor 可调用)
38
+
39
+ ### 3. method 调用类型检查修复(`preprocess.rs`)
40
+
41
+ 方法调用的 arg 类型检查循环中缺少对 `Variadic` 的处理,导致 `.union s1 s2` 误报。修复为与 `check_user_fn_arg_types` 一致的 Variadic 处理。
42
+
43
+ ### 4. calcit-core.cirru schema 修正
44
+
45
+ | 函数 | 修正内容 |
46
+ | --------------- | --------------------------------------------------------------------------------- |
47
+ | `every?` | `:args $ (:: :list :dynamic)` → `:dynamic`(接受 set) |
48
+ | `keys` | `:args $ :map` → `:dynamic`(接受 record) |
49
+ | `merge` | `:args $ :map` + `:rest $ :map` → `:dynamic`(接受 record) |
50
+ | `merge-non-nil` | 同上 |
51
+ | `reduce` | fn-arg 格式 `([] 'T 'U)(:: 'T 'U)` → `([] 'T 'U)([] 'T 'U)`(正确 generics+args) |
52
+ | `map` | fn-arg 格式 `([] 'T 'U)(:: 'T)` → `([] 'T 'U)([] 'T)`(正确 generics+1-arg) |
53
+
54
+ ## 验证
55
+
56
+ - `each ([] 1 2 3) 42` → 正确警告(42 不是 :fn)
57
+ - `reduce ([] 1 2 3) 0 &+` → 无误报(&+ 满足 fn(T,U)->T)
58
+ - `cargo test`:92 passed, 0 failed(之前 1 个失败的 test_examples_field_parsing 也通过了)
59
+ - `yarn check-all`:全量集成测试通过,0 warnings
60
+
61
+ ## 关键知识点
62
+
63
+ - `([] 'T 'U)` 是合法 Cirru EDN(`[]` 是合法 operator),`('T 'U)` 不合法(`'T` 不能作 operator)
64
+ - fn 类型 generics 列表格式:`([] 'T 'U)` 跳过 `[]` 头后得到 `[T, U]`
65
+ - fn 类型 args 列表格式:`([] :number :number)` 跳过 `[]` 头后得到 `[:number, :number]`
66
+ - `matches_signature` 不应检查 generics 数量——调用方传入的具体函数不声明 generics,但 TypeVar 绑定会在 args 匹配时解析
@@ -0,0 +1,82 @@
1
+ # 2026-0307-0142 `:unit` 类型 + 内建函数 schema 批量补全
2
+
3
+ ## 改动概要
4
+
5
+ ### 1. Rust 类型系统: `CalcitTypeAnnotation::Nil` (`:unit`)
6
+
7
+ 在 `src/calcit/type_annotation.rs` 中添加新的 `Nil` variant, 对应 Cirru 关键字 `:unit`。
8
+
9
+ **使用场景**: 副作用函数 (side-effectful functions), 明确标注返回 `nil` 的情况, 区别于 `:dynamic` (未知类型)。
10
+
11
+ **涉及改动点**:
12
+
13
+ - `CalcitTypeAnnotation` enum: 新增 `Nil` variant
14
+ - `builtin_type_from_tag_name`: `"unit" | "nil" => Self::Nil`
15
+ - `builtin_tag_name`: `Self::Nil => Some("unit")`
16
+ - `variant_order`: `Self::Nil => 27`
17
+ - `matches_with_bindings`: `(Self::Nil, Self::Nil) => true`
18
+ - `Hash impl`: `Self::Nil => "nil".hash(state)`
19
+ - `value_matches_type_annotation`: `CalcitTypeAnnotation::Nil => matches!(value, Calcit::Nil)`
20
+ - `gen_ir.rs`: `CalcitTypeAnnotation::Nil => type_tag_map("unit")`
21
+
22
+ ### 2. 副作用函数 `:return :unit` schema
23
+
24
+ 在 `src/cirru/calcit-core.cirru` 中为以下函数补充 `:return :unit` schema:
25
+
26
+ | 函数名 | schema 要点 |
27
+ | -------------- | ------------------------------------------------------- |
28
+ | `each` | `:args ([] :dynamic :fn) :return :unit` |
29
+ | `write-file` | `:args ([] :string :string) :return :unit` |
30
+ | `quit!` | `:args ([] (:: :optional :number)) :return :unit` |
31
+ | `add-watch` | `:args ([] :ref :dynamic :fn) :return :unit` |
32
+ | `remove-watch` | `:args ([] :ref :dynamic) :return :unit` |
33
+ | `reset!` | `:generics 'T :args ([] (:: :ref 'T) 'T) :return :unit` |
34
+
35
+ **注意事项**: 在 `:: :fn ('T) :unit` 中, `'T` 出现在 `('T)` 列表的算子位置会触发 EDN 解析错误 (`invalid operator for edn: 'T`)。对 `each` 的解决方案是简化成 `:fn`, 避免在 fn 参数类型中使用泛型变量作为算子。
36
+
37
+ ### 3. 内建函数 schema 批量补全 (54 条)
38
+
39
+ 对 `calcit-core.cirru` 中原本 `:schema nil` 的内建 primitive 函数批量补充类型:
40
+
41
+ **`&list:*` (16 条)**: `assoc`, `assoc-after`, `assoc-before`, `concat`, `contains?`, `count`, `dissoc`, `distinct`, `empty?`, `first`, `includes?`, `nth`, `rest`, `reverse`, `slice`, `to-set`
42
+
43
+ **`&map:*` (12 条)**: `assoc`, `common-keys`, `contains?`, `count`, `destruct`, `diff-keys`, `diff-new`, `dissoc`, `empty?`, `get`, `includes?`, `to-list`
44
+
45
+ **`&str:*` (15 条)**: `compare`, `concat`, `contains?`, `count`, `empty?`, `escape`, `find-index`, `first`, `includes?`, `nth`, `pad-left`, `pad-right`, `replace`, `rest`, `slice`
46
+
47
+ **集合操作 (10 条)**: `&difference`, `&exclude`, `&include`, `&set:count`, `&set:destruct`, `&set:empty?`, `&set:includes?`, `&set:intersection`, `&set:to-list`, `&union`
48
+
49
+ **泛型模式** (使用 `'T` 非算子位置):
50
+
51
+ ```cirru
52
+ {} (:kind :fn)
53
+ :generics $ [] 'T
54
+ :args $ [] (:: :list 'T) :number 'T
55
+ :return $ :: :list 'T
56
+ ```
57
+
58
+ ### 4. Clippy & 代码质量修复
59
+
60
+ - `emit_js.rs`: 消除冗余闭包 `xs.iter().skip(1).any(schema_marks_async)`
61
+ - `query.rs`: 添加复杂类型别名 `type RefResults = ...`
62
+
63
+ ## 技术知识点
64
+
65
+ ### `'T` 在 schema 文件中的限制
66
+
67
+ - **可用位置**: `:generics $ [] 'T`, `(:: :list 'T)` 的末尾参数, `[] :arg1 'T`
68
+ - **不可用位置**: `('T)` 即 `'T` 作为列表算子 (head), 例如 `(:: :fn ('T) :unit)` 中的 `('T)`
69
+ - **根本原因**: schema 验证通过 `cirru_edn::parse` 进行, EDN 解析器要求列表头部必须是合法算子
70
+
71
+ ### `:unit` vs `:dynamic`
72
+
73
+ - `:unit` — 明确标注 "此函数返回 nil, 且是预期行为" (副作用函数)
74
+ - `:dynamic` — 未知/任意类型 (默认回退)
75
+
76
+ ## 验证结果
77
+
78
+ ```
79
+ cargo clippy -- -D warnings → ✓ 0 warnings
80
+ cargo test → ✓ 17/17 passed
81
+ yarn check-all → ✓ took 571ms, all passed
82
+ ```
@@ -0,0 +1,32 @@
1
+ # 2026-03-07 CalcitAgent.md 文档更新
2
+
3
+ ## 修改内容
4
+
5
+ ### 1. 新增 `--no-tips` 全局标志文档
6
+
7
+ 在「主要运行命令」小节中,`cr js --check-only` 之后新增:
8
+
9
+ ```
10
+ - `cr --no-tips <subcommand> ...` - 隐藏所有编辑/查询命令输出的 "Tips:" 提示行(适合脚本/Agent 使用)
11
+ - 示例:`cr --no-tips demos/compact.cirru query def calcit.core/foldl`
12
+ ```
13
+
14
+ **背景**:`aa21b3a` 提交新增了 `--no-tips` 全局开关(`TIPS_SUPPRESSED: AtomicBool`,通过 `suppress_tips()` 设置),文档中缺少记录。
15
+
16
+ ### 2. 新增 HOF 高阶函数回调类型检查说明
17
+
18
+ 在「类型标注与检查 → 3. 支持的类型标签」之后,`约定:动态类型标注…` 注释的下方新增章节:
19
+
20
+ **高阶函数(HOF)回调类型检查:**
21
+ `foldl`、`sort`、`filter`、`find`、`find-index`、`filter-not`、`mapcat`、`group-by` 等内置 HOF 的回调参数已强制要求 `:fn` 类型,传入非函数值时预处理阶段会触发类型警告。附正/误示例。
22
+
23
+ **背景**:`aa21b3a` 提交修复了以下两条路径的类型检查:
24
+
25
+ - Cirru `defn` schema (`calcit-core.cirru`):`filter-not`/`find`/`find-index`/`foldl`/`foldl'`/`foldl-compare`/`mapcat`/`group-by`/`sort` 的回调参数由 `:dynamic` 改为 `:fn`(部分带泛型注解)
26
+ - `ProcTypeSignature` (`proc_name.rs`):`Foldl`/`Sort`/`FoldlShortcut`/`FoldrShortcut` 的回调参数 `dynamic` → `some_fn()`/`optional_fn()`
27
+
28
+ ## 知识点
29
+
30
+ - **文档中不需要描述 `ProTypeSignature` 实现细节**,面向 Agent 只需说明行为:哪些 HOF 要求 `:fn` 参数。
31
+ - **`--no-tips` 定位**:全局开关,放在 subcommand 前;所有 `Tips::print()` 调用均受其控制。
32
+ - CalcitAgent.md 未发现旧 `-s/--stdin` 残留,无需清理。
@@ -0,0 +1,112 @@
1
+ # 2026-0307-1652 — 解耦 snapshot::CodeEntry.schema 为 Arc<CalcitTypeAnnotation>
2
+
3
+ ## 核心改动
4
+
5
+ 将整个项目中 `snapshot::CodeEntry.schema` 和 `program::ProgramDefEntry.schema` 的类型,从 `Option<Edn>` / `Option<Arc<CalcitFnTypeAnnotation>>` 统一迁移为 `Arc<CalcitTypeAnnotation>`。
6
+
7
+ 同时打破了 `type_annotation.rs → program → snapshot → calcit` 的循环依赖。
8
+
9
+ ---
10
+
11
+ ## 循环依赖的解法
12
+
13
+ **原依赖链(错误):**
14
+
15
+ ```
16
+ snapshot → calcit::type_annotation → program → snapshot ❌
17
+ ```
18
+
19
+ **修复方案:** 在 `type_annotation.rs` 中用 `OnceLock<fn>` 注册 program 级别的 lookup 函数,由 `program.rs` 在 `extract_program_data` 时调用 `register_program_lookups` 完成注册:
20
+
21
+ ```rust
22
+ type LookupFn = fn(&str, &str) -> Option<Calcit>;
23
+ static LOOKUP_EVALED_DEF: OnceLock<LookupFn> = OnceLock::new();
24
+ static LOOKUP_DEF_CODE: OnceLock<LookupFn> = OnceLock::new();
25
+
26
+ pub fn register_program_lookups(evaled: LookupFn, code: LookupFn) {
27
+ let _ = LOOKUP_EVALED_DEF.set(evaled);
28
+ let _ = LOOKUP_DEF_CODE.set(code);
29
+ }
30
+ ```
31
+
32
+ ---
33
+
34
+ ## 修改文件列表
35
+
36
+ ### `src/calcit/type_annotation.rs`
37
+
38
+ - 移除 `use crate::program;` 导入
39
+ - 新增 OnceLock 静态注册机制及 `register_program_lookups` 公开函数
40
+ - 将 6 处 `program::lookup_*` 调用替换为本地 `lookup_evaled_def` / `lookup_def_code_registered`
41
+ - 新增 `CalcitTypeAnnotation::to_type_edn(&self) -> Edn` 序列化方法
42
+ - 新增 `calcit_type_to_edn(form: &Calcit) -> Edn` 私有辅助函数(Custom 类型回退)
43
+ - 新增 `CalcitFnTypeAnnotation::to_schema_edn(&self) -> Edn`(输出完整 schema map)
44
+ - 新增 `CalcitFnTypeAnnotation::to_schema_calcit(&self) -> Calcit`(用于 hint-fn 注入)
45
+ - 修复 `Self::Struct/Enum` 序列化:使用 `Edn::Tag` 而非 `Edn::Symbol`(类型不同)
46
+
47
+ ### `src/calcit.rs`
48
+
49
+ - 在 `pub use type_annotation::` 中新增 `register_program_lookups`
50
+
51
+ ### `src/program.rs`
52
+
53
+ - `ProgramDefEntry.schema: Arc<CalcitTypeAnnotation>`(取代旧 `Option<Arc<CalcitFnTypeAnnotation>>`)
54
+ - `extract_program_data` 首行调用 `calcit::register_program_lookups(...)`
55
+ - `lookup_def_schema` 返回类型改为 `Arc<CalcitTypeAnnotation>`(不再返回 Option,缺省返回 `DYNAMIC_TYPE`)
56
+ - `apply_code_changes` 中 `schema: DYNAMIC_TYPE.clone()` 取代 `None`
57
+
58
+ ### `src/snapshot.rs`
59
+
60
+ - 移除 `CalcitFnTypeAnnotation` 从导入(已无直接使用)
61
+ - 新增 `mod schema_serde`:将 `Arc<CalcitTypeAnnotation>` 序列化为 `Option<Edn>` 保持二进制 RMP 兼容
62
+ - `CodeEntry.schema: Arc<CalcitTypeAnnotation>`,带 `#[serde(default, with = "schema_serde")]`
63
+ - `TryFrom<Edn>` / `From` trait 实现全部更新,使用 `parse_fn_schema_from_edn` + `DYNAMIC_TYPE`
64
+ - 测试用例中 `schema: Some(Edn)` 改为通过 `parse_fn_schema_from_edn` 构造 `Arc<CalcitTypeAnnotation>`
65
+
66
+ ### `src/detailed_snapshot.rs`
67
+
68
+ - 同 `snapshot.rs` 模式:新增 `mod schema_serde`,字段类型改为 `Arc<CalcitTypeAnnotation>`
69
+ - `From<CodeEntry>` / `From<DetailedCodeEntry>` 均直接 clone Arc
70
+
71
+ ### `src/runner/preprocess.rs`
72
+
73
+ - hint-fn 注入改为先匹配 `CalcitTypeAnnotation::Fn(fn_annot)`,再调用 `fn_annot.to_schema_calcit()`
74
+
75
+ ### `src/bin/cli_handlers/edit.rs`
76
+
77
+ - schema 清空时:`schema = DYNAMIC_TYPE.clone()`
78
+ - schema 写入时:通过 `parse_fn_schema_from_edn` 解析后包装为 `Arc<CalcitTypeAnnotation::Fn(...)>`
79
+
80
+ ### `src/bin/cli_handlers/query.rs`
81
+
82
+ - 4 处 `entry.schema.is_some()` / `if let Some(schema_edn)` 全部改为 `CalcitTypeAnnotation::Fn(fn_annot)` 匹配
83
+ - 序列化时通过 `fn_annot.to_schema_edn()` 转回 Edn 后再调用 `schema_edn_to_cirru`
84
+
85
+ ### `src/bin/cr.rs`
86
+
87
+ - 新增 `CalcitTypeAnnotation` 到 `use calcit::{calcit::{...}}` 导入
88
+ - 原 `schema: None` 改为 `calcit::calcit::DYNAMIC_TYPE.clone()`
89
+ - `if let Some(schema_edn)` 改为 `if let CalcitTypeAnnotation::Fn(fn_annot)`
90
+
91
+ ### `src/bin/cr_sync.rs`
92
+
93
+ - `schema: None` 改为 `calcit::calcit::DYNAMIC_TYPE.clone()`
94
+
95
+ ---
96
+
97
+ ## 关键设计决策
98
+
99
+ 1. **`Arc<CalcitTypeAnnotation>` 永不为 None**:缺省值统一为 `DYNAMIC_TYPE`(全局 `LazyLock<Arc<CalcitTypeAnnotation>>` 单例),避免到处 `Option` 处理。
100
+
101
+ 2. **二进制兼容**:`schema_serde` 模块确保 `Dynamic` → 序列化为 `None`,`Fn(...)` → 序列化为完整 Edn map,与旧 `Option<Edn>` 格式一一对应。
102
+
103
+ 3. **`Edn::Tag` 用于类型名称**:`Struct`/`Enum` 类型序列化时用 `Edn::Tag(name)` 而非 `Edn::Symbol(name)`,因为 `EdnTag` 不能直接构造 `Edn::Symbol(Arc<str>)`。
104
+
105
+ ---
106
+
107
+ ## 验证结果
108
+
109
+ - `cargo build` ✅
110
+ - `cargo clippy -- -D warnings` ✅
111
+ - `cargo test` ✅(17 passed)
112
+ - `yarn check-all` ✅(515ms)
@@ -0,0 +1,6 @@
1
+ # 2026-0307-1821 Snapshot and Schema Serialization Refinement
2
+
3
+ - Verified Rust core changes using `yarn try-rs`, `cargo test`, and `yarn check-all`.
4
+ - Ensured `Snapshot` and `CodeEntry` serialization/deserialization remains consistent with the new direct map EDN format for schemas.
5
+ - Confirmed unit tests for `CodeEntry` with examples and schema validation are passing.
6
+ - Validated that `calcit-core.cirru` example parsing works as expected.
@@ -0,0 +1,96 @@
1
+ # Schema vs Definition Kind/Arity Validation
2
+
3
+ ## Summary
4
+
5
+ Added structural validation that compares a definition's code form against its schema declaration. This catch mismatches between declared schema metadata (`:kind`, arg count, rest param) and the actual `defn`/`defmacro` code at analysis time.
6
+
7
+ ## Key Changes
8
+
9
+ ### `src/calcit/type_annotation.rs`
10
+
11
+ 1. **Added `SchemaKind` enum** (`pub enum SchemaKind { Fn, Macro }`) — distinguishes `:kind :fn` from `:kind :macro` schemas.
12
+
13
+ 2. **Extended `CalcitFnTypeAnnotation`** with two new fields:
14
+ - `pub fn_kind: SchemaKind` — schema's declared kind (fn/macro).
15
+ - `pub rest_type: Option<Arc<CalcitTypeAnnotation>>` — schema's `:rest` type, if present.
16
+
17
+ 3. **`parse_fn_schema_from_edn`** — now reads `:kind :macro` → `SchemaKind::Macro` and `:rest` → `rest_type` from the EDN map.
18
+
19
+ 4. **`to_schema_edn`** — now serializes `fn_kind` (`fn`/`macro`) and `rest_type` (`:rest` key in the output map). Previously always emitted `:kind :fn` and omitted `:rest`.
20
+
21
+ 5. **All `CalcitFnTypeAnnotation` construction sites** updated to add `fn_kind: SchemaKind::Fn, rest_type: None` defaults (7 total).
22
+
23
+ 6. **`substitute_type_vars`** also propagates `fn_kind` and substitutes `rest_type`.
24
+
25
+ ### `src/calcit.rs`
26
+
27
+ - `SchemaKind` added to the `pub use type_annotation::{ ... }` re-export.
28
+
29
+ ### `src/bin/cr.rs`
30
+
31
+ 1. **`SchemaKind` imported** in the `use calcit::calcit::{...}` block.
32
+
33
+ 2. **`TypeCoverageRow` struct** gained `schema_issues: Vec<String>` field — carries kind/arity mismatch warnings per definition.
34
+
35
+ 3. **`validate_def_vs_schema(ns, def_name, code, schema) -> Vec<String>`** — new function:
36
+ - `&runtime-inplementation` leaf → skip (builtin proc/syntax).
37
+ - Schema not `CalcitTypeAnnotation::Fn` → skip.
38
+ - Code head not `defn`/`defmacro` → skip.
39
+ - Schema `:kind :fn` + code `defmacro` → error.
40
+ - Schema `:kind :macro` + code `defn` → error.
41
+ - Required arg count mismatch → error.
42
+ - `has_rest` mismatch (schema `:rest` vs code `&`) → error.
43
+
44
+ 4. **`analyze_param_arity(args: Option<&Cirru>) -> (usize, bool)`** — helper that counts required params and detects the `&` rest marker in a `defn`/`defmacro` args list.
45
+
46
+ 5. **`analyze_code_entry`** calls `validate_def_vs_schema` to populate `schema_issues` on each `TypeCoverageRow`.
47
+
48
+ 6. **`run_check_types` output loop** prints a `schema-issues:` section for rows with non-empty issues.
49
+
50
+ 7. **10 new unit tests** covering:
51
+ - `&runtime-inplementation` skip
52
+ - Correct defn/macro → no issues
53
+ - Kind mismatch (`:fn` vs `defmacro`, `:macro` vs `defn`)
54
+ - Arity mismatch
55
+ - Rest param mismatch
56
+ - `analyze_param_arity` basics
57
+ 8. **`CR_DEBUG_SCHEMA` debug flag** — when `CR_DEBUG_SCHEMA=1`, prints per-entry schema kind debug info to stderr during `analyze check-types`.
58
+
59
+ ### `src/runner/preprocess.rs`
60
+
61
+ 1. **Runtime/preprocess enforcement added** — schema-vs-definition structural checks now run while preprocessing `defn`/`defmacro`, not only in `analyze check-types`.
62
+ 2. **`validate_def_schema_during_preprocess(...)`** — mirrors the `check-types` validation for `:kind`, required arity, and `:rest`, and raises a hard `[Type Error]` during normal execution paths such as `yarn try-rs`.
63
+ 3. **Schema hints preserved** — preprocess still injects `hint-fn`, but now only after the definition passes structural schema validation.
64
+ 4. **2 new preprocess tests** covering arity mismatch and `:kind` mismatch at preprocess time.
65
+
66
+ ### `calcit/test-hygienic.cirru`
67
+
68
+ - Updated existing test fixture schemas so they match actual code:
69
+ - `add-11` / `add-11-safe`: `:kind :macro`
70
+ - `add-2`: arg schema corrected from 2 params to 1
71
+
72
+ ### `src/snapshot.rs`
73
+
74
+ - **`test_macro_schema_round_trip`** — verifies `schema_cirru_to_edn` + `parse_fn_schema_from_edn` + `normalize_schema_edn` preserve `SchemaKind::Macro` end-to-end.
75
+ - **`test_macro_schema_full_file_round_trip`** — verifies full `CodeEntry` serialize (`From<&CodeEntry> for Edn`) → `cirru_edn::format` → `cirru_edn::parse` → `TryFrom<Edn> for CodeEntry` round-trip preserves `fn_kind: Macro`.
76
+
77
+ ## Validation Rule Summary
78
+
79
+ | Schema `:kind` | Code form | Result |
80
+ | -------------- | ------------------------- | --------------- |
81
+ | `:fn` | `defn` | ✓ ok |
82
+ | `:fn` | `defmacro` | ✗ kind mismatch |
83
+ | `:macro` | `defmacro` | ✓ ok |
84
+ | `:macro` | `defn` | ✗ kind mismatch |
85
+ | any | `&runtime-inplementation` | ✓ skip |
86
+
87
+ Arg count and rest param are checked independently of kind.
88
+
89
+ ## Notes
90
+
91
+ - **`calcit.core` schemas require binary rebuild**: Schema edits to `src/cirru/calcit-core.cirru` do not take effect at runtime until the binary is rebuilt, because the core namespace is always loaded from the embedded `include_bytes!` snapshot produced by `build.rs`. Schema validation is most useful for user-defined namespaces.
92
+ - **Normal execution now checks schemas too**: before this follow-up, schema-vs-def mismatches were only reported by `analyze check-types`; now they fail fast during normal preprocess/runtime startup as well.
93
+
94
+ ## Test Results
95
+
96
+ All 125 tests pass (99 library + 26 binary), including 2 new snapshot round-trip tests and 2 new preprocess validation tests.
@@ -0,0 +1,35 @@
1
+ # Schema Generics Quote Normalization
2
+
3
+ ## Summary
4
+
5
+ Tightened schema loading so legacy generic symbols stored with embedded leading quotes now fail immediately, then normalized existing `calcit-core.cirru` schema generics from `''T`-style output to the correct `'T` source syntax.
6
+
7
+ ## Key Changes
8
+
9
+ - `src/calcit/type_annotation.rs`
10
+ - Stopped serializing schema generics as `Edn::Symbol("'T")`.
11
+ - Now writes plain EDN symbols like `Edn::Symbol("T")`, which format back to source as `'T`.
12
+ - Keeps compatibility when parsing previously saved legacy symbols, but normalizes them to plain names.
13
+
14
+ - `src/snapshot.rs`
15
+ - Added load-time rejection for legacy schema generic symbols carrying embedded leading quotes.
16
+ - Normalized schema EDN → Cirru conversion to go through format+parse so quoted symbols render correctly.
17
+ - Added regression tests for:
18
+ - single-quote round-trip,
19
+ - rejecting legacy quoted EDN symbols on load,
20
+ - rejecting `''T` on schema writes.
21
+
22
+ - `build.rs`
23
+ - Added the same legacy-generic rejection during build-time loading of `src/cirru/calcit-core.cirru`, so bad schema data fails `yarn check-all` immediately.
24
+
25
+ - `src/cirru/calcit-core.cirru`
26
+ - Replaced all legacy schema generic forms like `''T`, `''A`, `''K` with correct single-quoted forms.
27
+
28
+ - `docs/CalcitAgent.md`
29
+ - Updated schema/type-annotation guidance to reflect schema-first top-level typing and correct generic syntax examples.
30
+
31
+ ## Validation
32
+
33
+ - `cargo fmt`
34
+ - `cargo test schema_ -- --nocapture`
35
+ - `yarn check-all`
@@ -0,0 +1,34 @@
1
+ # 本次修改记录
2
+
3
+ ## 主题
4
+
5
+ - 完善 schema 类型系统:区分泛型变量与命名类型引用,支持 `'Result` 一类类型引用在 schema 中稳定往返。
6
+ - 继续推进 schema-first 迁移:清理 `calcit-core` 与若干测试文件中的 `assert-type`,将约束收敛到 `:schema` 与局部 `hint-fn`。
7
+ - 强化诊断:改进运行时参数个数错误与构建期 schema 解析报错,方便定位问题。
8
+
9
+ ## 主要改动
10
+
11
+ ### 1) Rust 侧类型系统收紧
12
+
13
+ - 在 `src/calcit/type_annotation.rs` 中新增命名类型引用分支,并让解析、匹配、显示、序列化都感知泛型作用域。
14
+ - `src/builtins/syntax.rs` 与 `src/builtins/records.rs` 改为按泛型上下文解析 schema,避免把命名类型误判成 type var。
15
+ - `src/codegen/gen_ir.rs`、`src/snapshot.rs` 同步适配新 schema 结构与 round-trip 测试。
16
+
17
+ ### 2) schema / hint-fn 迁移
18
+
19
+ - `src/cirru/calcit-core.cirru` 中移除剩余 `assert-type` 调用点,改为顶层 `:schema` 或局部 `hint-fn`。
20
+ - `calcit/test.cirru`、`calcit/debug/check-args.cirru`、`calcit/test-fn.cirru`、`calcit/test-types.cirru` 改用更精细的函数签名与局部约束。
21
+ - 修正函数类型直写 schema 的参数形式,统一使用 `([] ...)` 表达参数列表。
22
+
23
+ ### 3) 错误信息增强
24
+
25
+ - `src/runner.rs` 在参数个数不匹配时生成结构化报错,而不是直接触发内部 panic。
26
+ - `build.rs` 对 schema EDN 解析错误增加截断与整理,避免输出过长、难以定位。
27
+
28
+ ## 验证
29
+
30
+ - `cargo fmt` 通过。
31
+ - `cargo clippy -- -D warnings` 通过。
32
+ - `yarn compile` 通过。
33
+ - `cargo test` 通过。
34
+ - `yarn check-all` 通过。
@@ -0,0 +1,45 @@
1
+ # 2026-03-08 schema wrapper migration
2
+
3
+ ## Summary
4
+
5
+ - 统一函数 schema 的 snapshot 输出格式,顶层改为 wrapped `:: :fn` / `:: :macro` 形式。
6
+ - 修复 schema round-trip 中的类型信息丢失,确保嵌套函数类型与 `:rest` 在格式化后保持稳定。
7
+ - 将 macro schema 的顶层格式统一迁移到 `:: :macro`,并让 formatter 在处理 `defmacro` 条目时自动纠正旧的 `fn` 标记。
8
+ - 移除 legacy quote-wrapped schema normalization 与 legacy positional `fn` type annotation fallback,收紧到当前 schema-map 形式。
9
+ - 更新 `deftrait` 文档与相关说明,避免继续传播旧写法。
10
+
11
+ ## Main changes
12
+
13
+ ### 1) 顶层 schema 输出统一
14
+
15
+ - 在 `src/calcit/type_annotation.rs` 中补充顶层 wrapped schema 的解析与序列化逻辑。
16
+ - 在 `src/snapshot.rs` 中让 `CodeEntry.schema` 写回 snapshot 时统一输出为 `:schema $ :: :fn ...` 或 `:schema $ :: :macro ...`。
17
+ - 对 plain fn schema 去掉 wrapped payload 内冗余的 `:kind :fn`,但保留宏函数所需的 `:kind :macro`。
18
+
19
+ ### 2) macro schema 迁移与规范化
20
+
21
+ - 扩展 parser / normalize 逻辑,使其同时接受 wrapped `fn` 与 wrapped `macro`。
22
+ - 对 macro schema,序列化时省略冗余的 `:kind :macro` 与 `:return`,仅保留 `:args` 与可选 `:rest`。
23
+ - 在 snapshot 读写路径中,根据代码头是否为 `defmacro` 自动纠正 schema kind。
24
+
25
+ ### 3) legacy fn syntax 收紧
26
+
27
+ - 移除 legacy quote-wrapped schema normalization。
28
+ - 拒绝 legacy quoted generic symbols。
29
+ - 移除 legacy positional `fn` type annotation parsing fallback。
30
+ - 迁移剩余 core trait 与测试注解到 schema-map `:: :fn {}` 形式。
31
+
32
+ ### 4) round-trip 与批量格式化
33
+
34
+ - 修复 EDN 到 Calcit 的转换路径,补上 `Edn::Map` 的处理,避免嵌套 `fn` schema 的 hashmap payload 被吞掉后退化成 `:dynamic`。
35
+ - 调整 schema 校验与 normalize 逻辑,使 wrapped 顶层 fn schema 与旧格式都能稳定读写。
36
+ - 重新格式化了 `src/cirru/calcit-core.cirru`、`calcit/util.cirru`、`calcit/test-hygienic.cirru` 等兼容 snapshot 文件。
37
+
38
+ ## Validation
39
+
40
+ - `cargo fmt`
41
+ - `cargo clippy -- -D warnings`
42
+ - `yarn compile`
43
+ - `cargo test -q`
44
+ - `cargo build -q`
45
+ - `yarn check-all`
@@ -0,0 +1,27 @@
1
+ # 2026-03-08 late schema cleanup and warning compatibility
2
+
3
+ ## Summary
4
+
5
+ - made snapshot schema loading strict for non-nil schemas, so malformed schema data no longer silently degrades to dynamic
6
+ - normalized loaded schema maps so legacy string keys and string `:kind` values are converted into canonical tag-based schema maps
7
+ - restored generic type variables in `src/cirru/calcit-core.cirru` where a previous migration had incorrectly replaced them with `:symbol`
8
+ - cleaned the remaining mistaken `:symbol` placeholders in core collection schemas, keeping only the intentional `symbol?` runtime type check
9
+ - fixed `calcit/test-generics.cirru` after a schema-formatting edit moved `assert-type id ...` into the `let` binding section
10
+ - kept `ns/def` warning location reporting for embedded core snapshot loading
11
+ - stopped legacy fn-schema warnings from firing on malformed nested `:: :fn` schema payloads parsed from `calcit-core.cirru`
12
+ - used a conservative fallback to `DynFn` for malformed nested payloads, avoiding false-positive callback type warnings without re-editing Cirru syntax
13
+
14
+ ## Notes
15
+
16
+ - `yarn check-all` passed after the generic-schema restoration and remaining `:symbol` cleanup passes
17
+ - the `test-generics` fix resolves the runtime error `expected binding of a pair`
18
+ - nested function schema payloads coming from Cirru snapshot EDN may currently collapse into malformed map payloads like `(:: :fn ({} (nil ...)))` or `(:: :fn ({}))`
19
+ - those malformed payloads are lossy, so partially reconstructing arg/return types can introduce new static-analysis warnings
20
+ - decoding the embedded binary core snapshot with per-entry owners is necessary to preserve precise warning locations such as `calcit.core/foo`
21
+
22
+ ## Validation
23
+
24
+ - `cargo test -q malformed_nested_fn_schema`
25
+ - `cargo build -q`
26
+ - `target/debug/cr calcit/test.cirru -1`
27
+ - `yarn check-all`
@@ -0,0 +1,42 @@
1
+ # cr edit schema: support primitive type tag leaves
2
+
3
+ ## 背景
4
+
5
+ `cr edit schema` 原来只接受 `:: :fn $ {}` 这样的函数 schema 或 `{}` map 形式。
6
+ 有些定义的类型本身就是简单原始类型(如 `:string`、`:number`),不是函数,需要直接用 tag 表达。
7
+
8
+ ## 新语法
9
+
10
+ ```bash
11
+ cr edit schema 'respo.comp.space/style-space' --leaf -e ':string'
12
+ cr edit schema 'some.ns/my-val' --leaf -e ':number'
13
+ cr edit schema 'some.ns/my-flag' --leaf -e ':bool'
14
+ ```
15
+
16
+ 接受的 primitive 类型 tag:`bool`, `number`, `string`, `symbol`, `tag`, `list`, `map`, `set`, `fn`, `tuple`, `ref`, `buffer`, `dynamic`, `unit`
17
+
18
+ ## 改动文件
19
+
20
+ ### `src/calcit/type_annotation.rs`
21
+
22
+ - `builtin_tag_name` 改为 `pub(crate)`,供 snapshot 序列化侧调用。
23
+
24
+ ### `src/snapshot.rs`
25
+
26
+ - 新增常量 `PRIMITIVE_SCHEMA_TAGS`:列出允许作为 leaf schema 的原始类型。
27
+ - `validate_schema_for_write`:对 `Cirru::Leaf` 先检查是否在允许列表,允许则直接 Ok;否则给出提示信息。
28
+ - `parse_loaded_schema_annotation`:新增对 `Edn::Tag` 的处理,返回对应 `CalcitTypeAnnotation`。
29
+ - 两处 `CodeEntry::From` impl:`_ => Edn::Nil` 改为调用 `builtin_tag_name().map(Edn::tag)` 把原始类型 tag 正确序列化到快照。
30
+ - 测试 `test_validate_schema_for_write`:更新为测试原始类型 leaf 通过、未知 leaf 拒绝。
31
+
32
+ ### `src/bin/cli_handlers/edit.rs`
33
+
34
+ - `handle_schema`:`validate_schema_for_write` 通过后,若 `schema_payload` 是 `Cirru::Leaf`,用 `CalcitTypeAnnotation::from_tag_name` 直接设置 schema 并返回,不走函数 schema 解析路径。
35
+
36
+ ## 完整数据流(以 `:string` 为例)
37
+
38
+ 1. CLI 收到 `--leaf -e ':string'` → `Cirru::Leaf(":string")`
39
+ 2. `validate_schema_for_write` → `"string"` 在 `PRIMITIVE_SCHEMA_TAGS` → Ok
40
+ 3. `CalcitTypeAnnotation::from_tag_name("string")` → `CalcitTypeAnnotation::String`
41
+ 4. 写入快照 → `CodeEntry::From` 序列化为 `Edn::tag("string")`
42
+ 5. 读回快照 → `parse_loaded_schema_annotation(Edn::Tag("string"))` → `CalcitTypeAnnotation::String`
@@ -0,0 +1,17 @@
1
+ # schema type-fail tests and error codes
2
+
3
+ - 新增 `calcit/type-fail/` 下 schema 相关失败 fixture 的自动化测试,覆盖:
4
+ - `:args` required arity mismatch
5
+ - `:rest` presence mismatch
6
+ - `:kind` mismatch
7
+ - 基于 schema 的调用参数类型不匹配
8
+ - 在 `src/bin/cr.rs` 中补充 fixture 加载 helper,并通过 `run_check_only()` / preprocess warning 断言行为。
9
+ - 为类型/预处理相关告警补充 code:
10
+ - `W_FN_ARG_TYPE_MISMATCH`
11
+ - `W_PROC_ARG_TYPE_MISMATCH`
12
+ - `W_CORE_FN_ARG_TYPE_MISMATCH`
13
+ - `W_FN_RETURN_TYPE_MISMATCH`
14
+ - 为 schema 定义不匹配错误补充 code:
15
+ - `E_SCHEMA_DEF_MISMATCH`
16
+ - 为 `CalcitErr` 增加 `code` 字段和 `headline()`,让 CLI 输出可携带错误码。
17
+ - 更新 `calcit/type-fail/README.md`,记录自动化测试与当前相关 code。
@@ -0,0 +1,5 @@
1
+ # add test-fail script
2
+
3
+ - 在 `package.json` 中新增 `yarn test-fail`,用于日常单独执行 schema/type-fail 相关测试。
4
+ - 该命令当前映射到 `cargo test -q --bin cr type_fail_`,覆盖 `src/bin/cr.rs` 中新增的 fixture 测试。
5
+ - 更新 `calcit/type-fail/README.md`,补充 `yarn test-fail` 的使用说明。