@calcit/procs 0.12.54 → 0.12.56

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.
Binary file
package/README.md CHANGED
@@ -139,8 +139,9 @@ Run `caps` to download. Sources are downloaded into `~/.config/calcit/modules/`.
139
139
  To load modules, use `:modules` configuration and the runtime snapshot file `calcit.cirru` (legacy: `compact.cirru`):
140
140
 
141
141
  ```cirru
142
- :configs $ {}
143
- :modules $ [] |memof/calcit.cirru |lilac/
142
+ :entries $ {}
143
+ :default $ {}
144
+ :modules $ [] |memof/calcit.cirru |lilac/
144
145
  ```
145
146
 
146
147
  Paths defined in `:modules` field are just loaded as files from `~/.config/calcit/modules/`,
@@ -281,13 +281,15 @@ evaluate(with-type-slot body) -> 在遇到 dependency 时临时影响编译
281
281
 
282
282
  ### 8.2 已实现的配置语法
283
283
 
284
- 默认 entry 在 `:configs` 中绑定短 slot 名,值必须是完整 definition path 或 `:dynamic`:
284
+ 默认 entry 在 `:entries.default` 中绑定短 slot 名,值必须是完整 definition path 或 `:dynamic`:
285
285
 
286
286
  ```cirru
287
- :configs $ {}
288
- :init-fn |app.main/main!
289
- :type-slots $ {}
290
- :dispatch-op |app.schema/Op
287
+ :entries $ {}
288
+ :default $ {}
289
+ :mode :native
290
+ :init-fn |app.main/main!
291
+ :type-slots $ {}
292
+ :dispatch-op |app.schema/Op
291
293
  ```
292
294
 
293
295
  命名 entry 使用自己的完整配置,可以选择另一类型:
@@ -295,12 +297,13 @@ evaluate(with-type-slot body) -> 在遇到 dependency 时临时影响编译
295
297
  ```cirru
296
298
  :entries $ {}
297
299
  :server $ {}
300
+ :mode :native
298
301
  :init-fn |app.server/main!
299
302
  :type-slots $ {}
300
303
  :dispatch-op |app.schema/ServerOp
301
304
  ```
302
305
 
303
- 命名 entry 不继承默认 `:configs.type-slots`。这里使用完整 definition path,而不是在配置解析阶段求值任意 Calcit expression,因此配置可序列化、可查询,也不依赖入口函数的执行顺序。对应命令为:
306
+ 命名 entry 不继承 `:entries.default.type-slots`。这里使用完整 definition path,而不是在配置解析阶段求值任意 Calcit expression,因此配置可序列化、可查询,也不依赖入口函数的执行顺序。对应命令为:
304
307
 
305
308
  ```bash
306
309
  cr config set-type-slot :dispatch-op app.schema/Op
@@ -574,7 +577,7 @@ cr config type-slots --entry server
574
577
 
575
578
  ## 15. 尚待决定的问题
576
579
 
577
- 已决定:`:configs` 与每个命名 entry 各自保存完整 `:type-slots`,不做隐式继承;配置值只接受完整 definition path 或 `:dynamic`。
580
+ 已决定:所有入口统一存放在 `:entries`,`:default` 是无参数入口;每个 entry 各自保存完整 `:type-slots`,不做隐式继承;配置值只接受完整 definition path 或 `:dynamic`。
578
581
 
579
582
  仍待决定:
580
583
 
@@ -0,0 +1,170 @@
1
+ # RFC: `unsafe-coerce` 驱动的动态边界治理与静态类型强化计划
2
+
3
+ 状态:Draft
4
+ 日期:2026-07-31
5
+ 关联:`07-26-static-semantic-analysis-rfc.md`、`07-08-ffi-features-and-js-object-type-rfc.md`、`06-01-generic-binding-unification-rfc.md`
6
+
7
+ ## 1. 现状与目标
8
+
9
+ 我们将本阶段主目标聚焦在类型边界治理,而不是单纯推进 WASM 后端。
10
+ 针对 FFI(特别是 JS object)和外部大树形结构中大量动态值的问题,`unsafe-coerce` 要成为“静态分析可利用的类型入口点”,降低 `:dynamic` 退化。
11
+
12
+ 目标如下:
13
+
14
+ - 让动态边界明确化:能指出哪些值是故意进入静态盲区,哪些是可治理缺口;
15
+ - 提升静态可用信息:`unsafe-coerce` 后的类型关系要能在后续分析中被持续传播;
16
+ - 降低告警噪音:减少因隐式动态而产生的误报,转而给出可执行的收紧建议。
17
+
18
+ ## 2. 问题定义
19
+
20
+ 当前主要痛点是三类:
21
+
22
+ 1. 外部输入(JS Object、外部树形数据)一旦进入,会被频繁打散成 `:dynamic`;
23
+ 2. `unsafe-coerce` 当前只附加声明类型,不转换值,也不提供运行时校验,静态分析无法区分“推导所得”与“用户信任声明”;
24
+ 3. 未通过显式边界收敛的动态传播,会导致高阶函数、容器、回调、trait 调用处丧失可验证关系。
25
+
26
+ ## 3. 设计思路
27
+
28
+ 我们将类型边界分为五档,贯穿检查与诊断链路:
29
+
30
+ - `sealed-boundary`:明确的外部边界,需经过显式操作收窄;
31
+ - `trusted`:`unsafe-coerce` 给出的用户信任声明,可传播但不视为运行时证明;
32
+ - `validated`:由未来的实际校验操作建立的证据;
33
+ - `unvalidated`:未经过转换但可继续跟踪的弱上下文;
34
+ - `dynamic`:有意接受的动态盲区(可选 opt-in)。
35
+
36
+ `unsafe-coerce` 必须具备两个产出:
37
+
38
+ - 运行时行为:保持原值不变,不承诺验证;
39
+ - 静态元信息:来源类型、声明目标类型、边界位置和 `trusted` 置信等级。
40
+
41
+ 实际完成运行时验证的能力应使用独立操作,并把置信等级提升为 `validated`,不能由 `unsafe-coerce` 冒充。
42
+
43
+ ## 4. 规范草案
44
+
45
+ ### 4.1 `unsafe-coerce` 的静态签名
46
+
47
+ `unsafe-coerce` 调用应显式携带目标类型表达式,并在静态树或旁路分析元数据中记录:
48
+
49
+ - `from-type`:调用点推断来源;
50
+ - `to-type`:目标类型表达式;
51
+ - `confidence`:固定为 `trusted`,不可标为 `validated`;
52
+ - `evidence`:字段集合、泛型约束、变体等。
53
+
54
+ 示例:
55
+
56
+ ```cirru
57
+ unsafe-coerce user-json :js-object
58
+ unsafe-coerce user-json (:: :record User)
59
+ unsafe-coerce tree-data (:: :list (:: :ref TreeNode))
60
+ ```
61
+
62
+ ### 4.2 结构化构造的类型加强策略(enum / struct)
63
+
64
+ 当调用头能够静态确认就是某个 `defstruct` 或 `defenum` 定义时,类型收敛可走“无缝构造”策略,减少 `::` / `%::` / `%{}` 的显式写法。普通 record 实例或 enum tuple 即使携带相同类型信息,也不得被当作构造器:
65
+
66
+ - `enum`:在可推断为 enum 的位置,允许直接写 `Result :ok value`,由类型驱动 rewrite 成 `%:: Result :ok value`;
67
+ - `struct`:在可推断为结构体的上下文,允许按字段对写 `Person :name |Alice :age 20`,并在类型上下文中改写为 `%{} Person :name |Alice :age 20` 的有序结构构造;
68
+ - 规则约束仍保留:
69
+ - `struct` 必须是偶数个参数,按 key/value 成对出现;
70
+ - 字段不能重复;非 `:optional` 字段不能缺失;
71
+ - `enum` 的 tag 与 payload 必须匹配该 enum 的 variant;
72
+ - 任何 key 不在目标 struct 字段中的,回退到原有调用并给出 warning。
73
+
74
+ 示例:
75
+
76
+ ```cirru
77
+ let
78
+ maybe-ok $ Result :ok 1
79
+ person $ Person :name |Alice :age 20
80
+ ...
81
+ ```
82
+
83
+ 负向示例(应保持原样并给 warning):
84
+
85
+ ```cirru
86
+ Person :name |Alice :age
87
+ Result
88
+ Result :bad 1
89
+ Person :email |x
90
+ Result ok 1
91
+ kitty .rename |LagopusB
92
+ ```
93
+
94
+ 说明:
95
+
96
+ - `Person :email |x`:字段不在结构定义中 → 回退并 warning;
97
+ - `Person :name |Alice :age`:奇数参数 → 回退并 warning;
98
+ - `Result ok 1`:enum 首参不是 tag(需 `:ok`)→ 回退并 warning;
99
+ - `kitty .rename |LagopusB`:记录/结构方法调用不能被误判为构造调用。
100
+
101
+ ### 4.3 动态边界的使用规则
102
+
103
+ 1. 来自 FFI/主机接口的值默认进入 `sealed-boundary`;
104
+ 2. 若值要进入“纯 Calcit 计算路径”,必须通过 `unsafe-coerce` 进入可信声明类型,或通过实际校验操作进入已验证类型;
105
+ 3. 对容器与回调关系,`unsafe-coerce` 后应尽量保留内含关系(如 `:: :list T`、`:: :fn` 的参数/返回关联);
106
+ 4. 对于无法构建精确信息的对象(如完全开放结构),允许 `:dynamic`,但必须记录“故意动态”标签与边界位置。
107
+
108
+ ### 4.4 与现有警告体系对齐
109
+
110
+ - 引入/保留告警码:
111
+ - `W_SEALED_BOUNDARY_PASS`
112
+ - `W_MISSING_COERCE`
113
+ - `W_COERCE_COVERAGE_GAP`
114
+ - `W_DYNAMIC_EXIT`
115
+ - `unsafe-coerce` 使用不足的动态传播点应由 `W_MISSING_COERCE` 定位,并给出可替换的目标类型示例;
116
+ - `unsafe-coerce` 后仍不能稳定推断的情况,转为 `W_COERCE_COVERAGE_GAP` 并输出缺失字段/参数位置。
117
+
118
+ ### 4.5 与函数签名协同
119
+
120
+ `unsafe-coerce` 不是为了替代 schema,而是使 schema 可恢复:
121
+
122
+ - 大树节点进入列表/record 时,优先映射为命名结构体或 enum;
123
+ - 回调参数在边界后保持 `:fn` 的关系(arg/return / generics / where);
124
+ - 若同一结构反复出现,鼓励提升为 `defstruct` + `:where` + 类型参数,减少重复 `:dynamic`。
125
+
126
+ ## 5. 实施路线
127
+
128
+ ### Phase 1(1~2 周):把边界变可见
129
+
130
+ - 明确 `unsafe-coerce` 在静态元数据中的记录模型,并保证 local 场景不会擦除边界节点;
131
+ - 增加 `sealed-boundary` / `trusted` / `validated` / `unvalidated` / `dynamic` 标签在诊断中可见;
132
+ - 在 `type-at` 与 `check-types` 输出中显示 `unsafe-coerce` evidence 链路;
133
+ - 增加 `unsafe-coerce` 相关正向用例:JS Object → 记录/列表/enum。
134
+
135
+ ### Phase 2(2~3 周):增强 `unsafe-coerce` 的传播能力
136
+
137
+ - 在 container / fn / struct / enum 场景保留内含关系;
138
+ - 增强跨文件、跨 def 的类型传播,支持大树结构递归字段推断;
139
+ - 给 FFI 边界添加可执行的“首入场 unsafe-coerce 指南”(必须声明哪些层级,以及哪些位置需要真实校验)。
140
+
141
+ ### Phase 3(1~2 周):治理现有动态盲区
142
+
143
+ - 统计 `:dynamic` 产生原因:未转换、边界故意、兼容旧行为;
144
+ - 逐步把“可修复” `:dynamic` 转为结构化 `unsafe-coerce` 或真实校验,保留“故意动态”最小集合;
145
+ - 在 `analyze weak-types` 中增加类型边界报告:按定义、路径、优先级排序。
146
+
147
+ ## 6. 验收指标(建议)
148
+
149
+ 1. 关键 FFI 边界进入非纯路径时,`type-at` 能标出 `sealed-boundary`;
150
+ 2. 对树形/树状 JSON 数据,核心字段至少一层以上可从 `:dynamic` 收窄;
151
+ 3. 同一入口内的未转换动态访问点告警下降且可定位;
152
+ 4. 新增样例在 `check-types` 下可通过,不产生“类型丢失无法解释”的模糊告警。
153
+
154
+ ## 7. 风险与缓解
155
+
156
+ - 风险:`unsafe-coerce` 过度强约束导致现有生态迁移成本上升。
157
+ 缓解:保持 warning-first,逐步收紧。
158
+ - 风险:分析时间上升。
159
+ 缓解:对 `unsafe-coerce` evidence 做缓存并只在必要路径传播。
160
+ - 风险:FFI 数据本身不稳定结构导致验证失败。
161
+ 缓解:支持“部分声明 + `:dynamic` fallback”,让用户明确知道保留了什么边界。
162
+
163
+ ## 8. 依赖关系
164
+
165
+ 优先参考并复用:
166
+
167
+ - `06-01-generic-binding-unification-rfc.md`
168
+ - `07-26-static-semantic-analysis-rfc.md`
169
+ - `07-08-ffi-features-and-js-object-type-rfc.md`
170
+ - 现有类型诊断体系与 `analyze weak-types` 输出规范
package/build.rs CHANGED
@@ -6,16 +6,71 @@ use std::env;
6
6
  use std::fs;
7
7
  use std::path::Path;
8
8
 
9
+ #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
10
+ #[serde(rename_all = "lowercase")]
11
+ pub enum SnapshotRunMode {
12
+ #[default]
13
+ Native,
14
+ Js,
15
+ }
16
+
17
+ fn deserialize_run_mode<'de, D>(deserializer: D) -> Result<SnapshotRunMode, D::Error>
18
+ where
19
+ D: serde::Deserializer<'de>,
20
+ {
21
+ let value = Edn::deserialize(deserializer)?;
22
+ let mode = match value {
23
+ Edn::Tag(tag) => tag.ref_str().to_owned(),
24
+ Edn::Str(text) | Edn::Symbol(text) => text.trim_start_matches(':').to_owned(),
25
+ other => return Err(serde::de::Error::custom(format!("expected :native or :js, got {other:?}"))),
26
+ };
27
+ match mode.as_str() {
28
+ "native" => Ok(SnapshotRunMode::Native),
29
+ "js" => Ok(SnapshotRunMode::Js),
30
+ _ => Err(serde::de::Error::custom(format!("expected :native or :js, got {mode}"))),
31
+ }
32
+ }
33
+
34
+ fn deserialize_ns_def<'de, D>(deserializer: D) -> Result<String, D::Error>
35
+ where
36
+ D: serde::Deserializer<'de>,
37
+ {
38
+ match Edn::deserialize(deserializer)? {
39
+ Edn::Str(text) | Edn::Symbol(text) => Ok(text.to_string()),
40
+ other => Err(serde::de::Error::custom(format!(
41
+ "expected namespace/definition string or symbol, got {other:?}"
42
+ ))),
43
+ }
44
+ }
45
+
9
46
  #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10
- pub struct SnapshotConfigs {
11
- #[serde(rename = "init-fn")]
47
+ pub struct SnapshotEntry {
48
+ #[serde(default, deserialize_with = "deserialize_run_mode")]
49
+ pub mode: SnapshotRunMode,
50
+ #[serde(rename = "init-fn", deserialize_with = "deserialize_ns_def")]
12
51
  pub init_fn: String,
13
- #[serde(rename = "reload-fn")]
52
+ #[serde(rename = "reload-fn", deserialize_with = "deserialize_ns_def")]
53
+ pub reload_fn: String,
54
+ #[serde(default)]
55
+ pub description: String,
56
+ #[serde(default)]
57
+ pub modules: Vec<String>,
58
+ #[serde(default, rename = "type-slots")]
59
+ pub type_slots: HashMap<String, String>,
60
+ }
61
+
62
+ #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
63
+ pub struct LegacySnapshotConfigs {
64
+ #[serde(rename = "init-fn", deserialize_with = "deserialize_ns_def")]
65
+ pub init_fn: String,
66
+ #[serde(rename = "reload-fn", deserialize_with = "deserialize_ns_def")]
14
67
  pub reload_fn: String,
15
68
  #[serde(default)]
16
69
  pub modules: Vec<String>,
17
70
  #[serde(default)]
18
71
  pub version: String,
72
+ #[serde(default, rename = "type-slots")]
73
+ pub type_slots: HashMap<String, String>,
19
74
  }
20
75
 
21
76
  #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
@@ -46,8 +101,9 @@ pub struct FileInSnapShot {
46
101
  pub struct Snapshot {
47
102
  pub package: String,
48
103
  pub about: Option<String>,
49
- pub configs: SnapshotConfigs,
50
- pub entries: HashMap<String, SnapshotConfigs>,
104
+ #[serde(default)]
105
+ pub version: String,
106
+ pub entries: HashMap<String, SnapshotEntry>,
51
107
  pub files: HashMap<String, FileInSnapShot>,
52
108
  }
53
109
 
@@ -417,11 +473,37 @@ fn main() {
417
473
 
418
474
  let files = parse_files(data.get_or_nil("files")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:files`: {e}"));
419
475
 
476
+ let legacy_configs = match data.get_or_nil("configs") {
477
+ Edn::Nil => None,
478
+ value => {
479
+ Some(from_edn::<LegacySnapshotConfigs>(value).unwrap_or_else(|e| panic!("failed to parse calcit-core legacy `:configs`: {e}")))
480
+ }
481
+ };
482
+ let mut entries: HashMap<String, SnapshotEntry> =
483
+ from_edn(data.get_or_nil("entries")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:entries`: {e}"));
484
+ if let Some(configs) = &legacy_configs {
485
+ entries.insert(
486
+ "default".to_owned(),
487
+ SnapshotEntry {
488
+ mode: SnapshotRunMode::Native,
489
+ init_fn: configs.init_fn.clone(),
490
+ reload_fn: configs.reload_fn.clone(),
491
+ description: String::new(),
492
+ modules: configs.modules.clone(),
493
+ type_slots: configs.type_slots.clone(),
494
+ },
495
+ );
496
+ }
497
+ let version = match data.get_or_nil("version") {
498
+ Edn::Nil => legacy_configs.map(|configs| configs.version).unwrap_or_default(),
499
+ value => from_edn(value).unwrap_or_else(|e| panic!("failed to parse calcit-core `:version`: {e}")),
500
+ };
501
+
420
502
  let snapshot = Snapshot {
421
503
  package: pkg,
422
504
  about,
423
- configs: from_edn(data.get_or_nil("configs")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:configs`: {e}")),
424
- entries: from_edn(data.get_or_nil("entries")).unwrap_or_else(|e| panic!("failed to parse calcit-core `:entries`: {e}")),
505
+ version,
506
+ entries,
425
507
  files,
426
508
  };
427
509
 
@@ -0,0 +1,6 @@
1
+ # Program diff 补齐 entry type slots
2
+
3
+ - `SnapshotConfigs.type_slots` 已用于默认 `:configs` 和命名 `:entries`,但 program diff 仍只枚举旧的 `init-fn`、`reload-fn`、`version` 与 `modules` 字段,导致纯 type-slot 修改被误报为无变化。
4
+ - 为字符串 map 增加稳定按 key 排序的结构化 diff,slot 标签保留 `:dispatch-op` 形式;新增或删除整个 entry 时也完整展示其 type slots。
5
+ - `Snapshot` 与 `SnapshotConfigs` 的 program diff 改为无 `..` 的完整字段解构。以后新增字段而未更新 diff 时会产生编译错误,避免同类静默遗漏。
6
+ - 回归测试覆盖默认 entry 的 slot 新增、删除、替换,命名 entry 的 slot 修改,以及新增 entry 时的 slot 详情。
@@ -0,0 +1,7 @@
1
+ # Unify snapshot entries and run modes
2
+
3
+ - Replaced the split top-level `:configs` plus `:entries` model with a single `:entries` map. `:default` is now the required implicit entry and the project version lives at top-level `:version`.
4
+ - Added entry-level `:mode` with the supported values `:native` and `:js`. A bare `cr <snapshot> [--entry name]` now follows the selected entry's mode; the explicit `js` subcommand remains available as an override.
5
+ - Kept legacy snapshot loading compatible: old `:configs` is migrated in memory to `entries.default` with native mode, while canonical writes emit only the unified schema.
6
+ - Updated config/query/diff/type-slot/module selection, embedded core serialization, repository snapshots, bundle/sync scripts, CLI help, RFCs, and user/Agent documentation.
7
+ - Added coverage for new-format round trips, legacy migration, configured JS dispatch, and default-entry module extraction.
@@ -0,0 +1,7 @@
1
+ # Entry description snapshot metadata
2
+
3
+ - `SnapshotEntry` now carries an optional `description` string for semantic context about an executable entry.
4
+ - Existing snapshots without `:description` remain valid and deserialize to an empty string; canonical snapshot writes include the field.
5
+ - Keep the build-script snapshot model synchronized with runtime `SnapshotEntry`, otherwise the embedded core MessagePack snapshot cannot be decoded.
6
+ - `cr config set [--entry <name>] description "..."` updates the field, and `cr config show` displays it.
7
+ - Program diffs expose description changes independently from runtime configuration and type-slot changes.
@@ -0,0 +1,6 @@
1
+ # Initialize entry descriptions in repository snapshots
2
+
3
+ - Installed the current `cr` 0.12.54 binary globally from this checkout.
4
+ - Used `cr <snapshot> config set description ''` to canonicalize every complete `calcit/**/*.cirru` snapshot.
5
+ - The migration updates 58 snapshots and 60 entry configurations, including named entries, with an explicit empty `:description` field.
6
+ - Empty values preserve existing runtime behavior while providing a stable place for future semantic descriptions.
@@ -0,0 +1,7 @@
1
+ # Store entry functions as Calcit symbols
2
+
3
+ - `:init-fn` and `:reload-fn` describe namespace/definition references, so canonical snapshot output now writes them as Cirru EDN symbols such as `'app.main/main!`.
4
+ - Snapshot readers continue to accept the prior string form (`|app.main/main!`) for compatibility.
5
+ - The embedded core-snapshot build model accepts either representation when deserializing entry metadata.
6
+ - Reinstalled `cr` globally and used it to rewrite all `calcit/**/*.cirru` snapshots; 120 entry function references now use symbols.
7
+ - Updated snapshot documentation and round-trip coverage to make the canonical syntax explicit.
@@ -0,0 +1,5 @@
1
+ # Release 0.12.55
2
+
3
+ - Bumped the Rust crate and npm package versions together to `0.12.55`.
4
+ - Refreshed the workspace lockfile before the release commit.
5
+ - This release includes semantic snapshot entry descriptions and canonical symbol storage for entry functions, while preserving legacy string input compatibility.
@@ -0,0 +1,23 @@
1
+ # Strengthen namespace import diagnostics
2
+
3
+ ## Summary
4
+
5
+ - Replaced namespace/import parser panics and silent fallbacks with contextual errors for malformed namespace forms, short rules, invalid rule kinds, and invalid node shapes.
6
+ - Added one shared import-rule validator for program loading and `cr edit add-import` / `cr edit imports`, so invalid edits are rejected before the snapshot is saved.
7
+ - Detect duplicate local bindings across rules and repeated `:refer` definitions within one rule instead of silently overwriting the earlier import.
8
+ - Preserved legacy `(:ns namespace)` compatibility while validating supported `:require` structures.
9
+ - Clarified that `call-graph --show-unused` reports definitions unreachable from the selected entry, not proven dead code or unused import declarations.
10
+ - Kept unused-definition analysis independent from `--max-depth`, preventing display truncation from producing false dead-code reports.
11
+ - Documented validation behavior, atomic edits, dead-code analysis limits, and the relevant CLI workflow.
12
+
13
+ ## Validation
14
+
15
+ - `cargo fmt`
16
+ - `cargo clippy -- -D warnings`
17
+ - `cargo test`
18
+ - `yarn compile`
19
+ - `yarn check-all`
20
+ - `yarn check-agent-interface` (12/12 scenarios)
21
+ - `cr docs check-md docs/features/imports.md --entry calcit/test.cirru` (4/4 blocks)
22
+ - Isolated CLI regressions confirming malformed and duplicate imports are rejected without changing the snapshot.
23
+ - Compared `call-graph --show-unused` with unlimited depth and `--max-depth 1`; unused-definition results are identical.
@@ -0,0 +1,20 @@
1
+ # Strengthen unsafe-coerce boundaries
2
+
3
+ ## Summary
4
+
5
+ - Kept `unsafe-coerce` visible in preprocessed expressions instead of mutating the source local's type globally, preserving a stable boundary node for later static evidence reporting.
6
+ - Added type-directed shorthand construction for confirmed `defstruct` and `defenum` definitions while preventing record and enum tuple instances from being treated as constructors.
7
+ - Validated shorthand struct fields for pair shape, membership, duplication, required-field coverage, and statically known value type mismatches.
8
+ - Reused typed record and enum constructor nodes so native, JavaScript, and WASM backends receive their existing canonical forms.
9
+ - Documented the boundary model, distinguishing trusted `unsafe-coerce` declarations from future runtime-validated evidence.
10
+ - Added positive and negative preprocessing coverage for constructor rewrites, invalid variants, malformed fields, method syntax, and instance/prototype separation.
11
+
12
+ ## Validation
13
+
14
+ - `cargo fmt`
15
+ - `cargo clippy -- -D warnings`
16
+ - `cargo test`
17
+ - `yarn compile`
18
+ - `yarn check-agent-interface` (12/12 scenarios)
19
+ - `yarn check-all` (native, JavaScript, and WASM checks passed)
20
+ - Current debug `cr --check-only` against `/Users/jon.chen/repo/respo/respo/calcit.cirru`
@@ -0,0 +1,18 @@
1
+ # Warn on duplicate imports
2
+
3
+ - Changed duplicate namespace import bindings from validation errors to recoverable warnings on stderr.
4
+ - Preserved the existing last-rule-wins behavior so duplicate aliases and repeated `:refer` entries do not stop program execution.
5
+ - Kept malformed import structures, invalid rule kinds, and invalid node shapes as errors.
6
+ - Updated CLI editing to save valid duplicate imports after displaying the warning.
7
+ - Added tests for warnings and last-rule-wins resolution, plus an isolated CLI/runtime regression proving execution continues.
8
+ - Updated import documentation to distinguish recoverable duplicate bindings from malformed rules.
9
+
10
+ ## Validation
11
+
12
+ - `cargo fmt`
13
+ - `cargo clippy -- -D warnings`
14
+ - `cargo test`
15
+ - `yarn compile`
16
+ - `yarn check-all`
17
+ - `yarn check-agent-interface` (12/12 scenarios)
18
+ - `cr docs check-md docs/features/imports.md --entry calcit/test.cirru`
@@ -0,0 +1,15 @@
1
+ # Release 0.12.56
2
+
3
+ ## Summary
4
+
5
+ - Bump the Calcit Rust crate and npm package versions from `0.12.55` to `0.12.56`.
6
+ - Refresh the workspace lockfile so package metadata remains consistent.
7
+
8
+ ## Validation
9
+
10
+ - `cargo fmt --check`
11
+ - `cargo clippy -- -D warnings`
12
+ - `yarn compile`
13
+ - `cargo test`
14
+ - `yarn check-all`
15
+ - `yarn check-agent-interface`
@@ -0,0 +1,23 @@
1
+ # Library quality gates and format advisories
2
+
3
+ ## Summary
4
+
5
+ - Add a dedicated Calcit library/module acceptance guide covering Snapshot canonicalization, entries, type slots, weak-type baselines, examples, Markdown checks, entry/backend validation, call-graph limits, consumer regression, and CI evidence.
6
+ - Refresh the project upgrade guide for once-by-default execution, entry modes, unified `:entries`, per-entry type slots, canonical `:dynamic`, and current static-analysis commands.
7
+ - Extend `cr edit format` with recoverable advisories for legacy `:configs`, the `compact.cirru` filename, legacy `:any`, and unresolved dynamic type debt.
8
+ - Keep formatting non-blocking for quality debt and direct users to `check-types` / `weak-types` for semantic paths and recommendations.
9
+
10
+ ## Validation
11
+
12
+ - `cargo fmt`
13
+ - `cargo clippy -- -D warnings`
14
+ - focused `cr` format advisory unit tests
15
+ - `cargo test`
16
+ - `yarn compile`
17
+ - `yarn check-all`
18
+ - `yarn check-agent-interface`
19
+ - `cr docs graph check`
20
+ - `cr docs check-md docs/run/library-quality.md`
21
+ - `cr docs check-md docs/run/upgrade.md`
22
+ - legacy config and filename formatting on temporary Snapshots
23
+ - Respo consumer regression on a temporary Snapshot: format, config show, weak-types summary, and `--check-only`
package/lib/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.12.54",
3
+ "version": "0.12.56",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.7.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@calcit/procs",
3
- "version": "0.12.54",
3
+ "version": "0.12.56",
4
4
  "main": "./lib/calcit.procs.mjs",
5
5
  "devDependencies": {
6
6
  "@types/node": "^25.7.0",