# `cr query def` / `cr tree show` 分片展示方案

## 目标

当定义或子树比较小时，继续保持当前直接输出的体验。

当表达式足够大时，切换到“分片展示”模式，满足下面几点：

- 保留一个可快速阅读的根视图；
- 用占位符替换体积过大的子树；
- 按坐标顺序输出被拆出的片段；
- 允许通过参数调整每个片段期望容纳的节点数；
- 输出与文档优先使用点号路径，同时兼容逗号路径输入。

## 选定案例

本次以 `find-children-diffs` 作为主案例。

原因：

- 它已经足够大，能明显暴露当前整块输出的可读性问题；
- 它内部天然存在 `cond`、嵌套 `let`、局部分支组等适合作为切分边界的结构；
- 它贴近真实工作流，既适合人阅读，也适合作为 LLM 分治理解的目标。

## 对比结论

### 基线：直接整块输出

当前的 `cr query def` 会一次性打印完整定义。

当前的 `cr tree show` 会打印目标子树，然后列出直接子节点路径。

这个方案在小表达式上没有问题，但面对大表达式时会出现这些缺点：

- 主流程和局部细节混在一起，不容易先抓到整体结构；
- 重复性的局部绑定会占掉大量屏幕；
- 用户必须反复在 `search`、`show`、原始代码块之间切换；
- LLM 容易被附近细节吸住，反而丢掉更高层的分支关系。

### 1 倍预算

较早实验里，`find-children-diffs` 的目标片段大小大约是 `24` 个节点。

这一版会被拆成 `14` 个片段，很多片段落在 `19-39` 节点之间。结构虽然有效，但整体仍然偏碎，不利于连续阅读。

### 2 倍预算

把目标片段大小提高到大约 `48` 个节点后，同一个案例会变成 `9` 个片段：

- `75, 57, 55, 53, 53, 42, 41, 39, 35`

这一版更适合作为默认方案，原因是：

- 顶层控制流可以一眼看清；
- 局部初始化逻辑更容易整体保留；
- 片段数足够少，可以顺序浏览；
- 切分边界看起来更接近语义单元，而不是机械按大小切开。

## 表达式拆分示例

下面用一个简化的表达式说明“整块输出”和“分片输出”的区别。

原始表达式：

```cirru
let
    a $ compute-a x
    b $ compute-b x
  cond
      ready? a b
      handle-ready a b
    fallback?
      let
          details $ build-details a b
          view $ render-view details
        emit! view
        track! details
    true
      let
          err $ build-error a b
        warn err
        recover err
```

分片展示后，根片段会更像这样：

```cirru
ROOT at root
let
    a $ compute-a x
    b $ compute-b x
  cond
      ready? a b
      handle-ready a b
    fallback?
      {{let_emit_track_01}}@2.2
    true
      {{let_warn_recover_02}}@2.3
```

再继续列出拆出的片段：

```cirru
{{let_emit_track_01}} at 2.2
let
    details $ build-details a b
    view $ render-view details
  emit! view
  track! details

{{let_warn_recover_02}} at 2.3
let
    err $ build-error a b
  warn err
  recover err
```

这样做的好处是：

- 根片段只保留主流程；
- 细节块被移动到后面，阅读顺序更清晰；
- 每个占位符都带精确坐标，仍然能回到原树上继续定位或编辑。

## 决策

默认采用“递归语义切分”作为大表达式的展示策略。

更具体地说：

- 以现有递归语义启发式为基础；
- 只有当表达式超过某个可配置阈值时才启用分片；
- 默认预算采用比早期实验更宽松的配置；
- 保留 `--raw` 作为脚本和精确检查时的逃生口。

## 预期交互

### `cr query def`

对于较小定义：

- 保持现在的直接输出。

对于较大定义：

- 元信息照常输出；
- 用 `Chunked Cirru:` 替代一整块超长 Cirru；
- 先打印根片段，再按坐标顺序打印拆出的片段；
- 每个片段展示：坐标、节点数、最大深度、Cirru 内容。

### `cr tree show`

对于较小子树：

- 保持现在的输出形状。

对于较大子树：

- 先展示节点类型和子树统计；
- 再展示分片后的根预览；
- 后续继续列出拆出的片段；
- 子节点导航提示仍然基于原始树路径；
- 用户可以直接根据片段坐标继续向下钻取。

## CLI 参数设计

这些参数应同时提供给 `cr query def` 和 `cr tree show`：

- `--chunk-target-nodes <n>`：每个片段理想节点数；
- `--chunk-max-nodes <n>`：停止继续细分前允许的软上限；
- `--chunk-trigger-nodes <n>`：总节点数低于该值时不启用分片；
- `--raw`：强制回退到旧的整块输出。

当前建议默认值：

- `chunk-target-nodes = 56`
- `chunk-max-nodes = 68`
- `chunk-trigger-nodes = 88`

原因：

- `target` 需要足够大，避免过度切碎；
- `max` 略高于 `target`，避免为了几颗节点继续无意义细分；
- `trigger` 需要过滤掉本来还能整体阅读的中等表达式。

## 路径方案

### 输出格式

所有新的展示输出统一优先使用点号路径，例如：

- `3.2.4.1.1`

这样和前面的分片研究保持一致，也更方便人和 LLM 直接复制。

### 输入兼容

路径输入保持两种写法都支持：

- 逗号：`3,2,4,1,1`
- 点号：`3.2.4.1.1`

规则：

- 空字符串仍表示根节点；
- 同一路径里混用点号和逗号时直接报错，避免静默歧义；
- 文档只主推点号写法，逗号作为兼容行为说明一次即可。

## 内部实现计划

### 1. 提取可复用的分片模块

把展示侧的切分逻辑从实验脚本迁移到 Rust，形成独立的 CLI 辅助模块。

职责包括：

- 计算节点统计信息；
- 收集候选子树；
- 基于递归语义策略选择切点；
- 生成占位符；
- 输出有序分解结果；
- 统一格式化路径。

### 2. 第一阶段只做展示层改造

第一阶段不修改 snapshot 存储、不修改 AST 语义、不修改编辑行为。

仅让 `query def` 与 `tree show` 使用新的分片渲染。

### 3. 集中处理路径兼容

扩展公共路径解析逻辑，让各 CLI handler 都能接受点号路径，而不是每个命令各自手写兼容。

同时增加统一的路径格式化函数，避免到处手写 `join(",")` 或 `join(".")`。

### 4. 更新命令处理逻辑

`handle_def`：

- 先计算定义总节点数；
- 根据阈值决定直接输出还是分片输出；
- 保持 `--json` 行为不变。

`handle_show`：

- 先计算目标子树节点数；
- 根据阈值决定直接输出还是分片输出；
- 保持子节点导航提示和替换提示。

### 5. 文档迁移

把文档示例统一调整为优先使用点号路径，例如：

```bash
cr tree show ns/def -p '3.2.1'
```

逗号兼容只在合适位置说明一次，不重复铺满全文。

## 风险与应对

### 风险：展示过于“魔法化”

应对：

- 保留 `--raw`；
- 明确打印分片统计信息；
- 每个片段都保留精确坐标。

### 风险：点号路径与命名空间里的点冲突

应对：

- 点号/逗号解析只作用于路径参数；
- 不把这套解析逻辑用于 `ns/def` 目标字符串。

### 风险：分片展示影响编辑工作流

应对：

- 分片只影响展示，不影响数据结构；
- 真正的编辑命令仍然对原始树坐标生效。

## 推进顺序

1. 先写这份方案文档。
2. 在 Rust 中加入可复用的分片与路径辅助逻辑。
3. 把分片渲染接入 `cr query def`。
4. 把分片渲染接入 `cr tree show`。
5. 加入点号路径兼容。
6. 更新文档，主推点号路径。
7. 用 `find-children-diffs` 做真实案例验证，并微调默认值。

## 验收标准

- `cr query def` 在大定义上默认输出分片结果；
- `cr tree show` 在大子树上默认输出分片结果；
- 两个命令都支持 `--chunk-target-nodes`；
- 两个命令都接受点号路径；
- 逗号路径保持兼容；
- 文档示例优先使用点号路径；
- `--raw` 可以恢复旧的整块输出行为。
