# 三层树设计(index / nodes) > 2026-10-28 · 记录「棋谱文件树」的设计依据、六个实测缺陷与最终形态。 ## 为什么是树 + 扁平的混合 棋谱是 **DAG**(有向无环图),不是树: | 指标 | 实测值(session-5acafe42) | |---|---| | 节点 | 253 | | 边 | 427 | | 多父节点 | 7 个(3.4%) | | **最大入度** | **119**(n174 有 119 个父) | | transposition 边占比 | **61%** | **纯目录嵌套(父节点 → 子文件夹)会让 n174 在 119 个目录里重复 119 份** —— 文件爆炸 + 不同步。 **SGF(围棋标准棋谱格式)是树**(`[SGF FF[4]](https://www.red-bean.com/sgf/)`:text only, tree based format),因为实际对局局面**不重复**。Agent 棋谱**会重复**(同一文件、同一错误),所以不能用 SGF 的树形嵌套。 **最终形态**: ``` sessions// ├── index.md 缩进树(每节点只出现一次)+ 失败边全表 ├── nodes/.md 单节点:评语 / 状态 / 入边 / 出边 / verify └── graph.json 数据源(插件恢复用) ``` **缩进 = 深度**(SGF 风格),**每个节点只出现一次**(DAG 风格)。 ## 每一层的作用与消费者 | 文件 | 内容 | 谁用 | 频率 | |---|---|---|---| | `index.md` 缩进树 | 落子顺序 + 每条出边状态 | 模型先读 | 每次 need | | `index.md` 失败边全表 | 所有 failure(含跨边/置换边) | 模型枚举全部失败时 | 偶尔 | | `nodes/.md` | 评语 / 状态 / 入边 / 出边 / `[verify:kind]` / `[text:?]` | 模型按需读 | 按需 | | `graph.json` | 完整数据 | 插件自己(恢复) | 每次启动 | ## 六个实测缺陷(子代理驱动) 两个隔离子代理只靠三层树回答「这个会话试过哪些失败路径」,报了 6 个缺陷: | # | 缺陷 | 修法 | 版本 | |---|---|---|---| | 1 | **原因缺失**:98 条 failure 只有 13 条带附注 | `errorSnippet` 截断 100 → **400** | v1.2.6 | | 2 | **意图缺失**:200 节点只有 7 个有 `goal` | 评语兜底:`goal` → 入边 `intent` → 入边 `action`(标注「非 LLM 原话」) | v1.2.7 | | 3 | **节点缺失**:只写 `g.order`,被合并且仍被边引用的没有 md | 写**所有** `g.nodes` | v1.2.6 | | 4 | **index 只列 190/404 条边**:缩进树每节点只出现一次 | 加「**失败边全表**」段 | v1.2.6 | | 5 | **标签不可信**:43/98 是 verifier 误报(`text` 型) | 失败边带 `[verify:kind]` + `[text:?]` | v1.2.7 / v1.3.0 | | 6 | **读时重建不一致**:index 187/383 vs graph.json 229/421 | 写顺序:先 md 后 json(json 是提交点);index 头部带 `updated` | v1.2.8 | ## 三条核心教训 ### 1. 结构对了不等于内容对了 三层树的结构(index / nodes / 原始)是对的,但**写进去的内容不全** —— `errorSnippet` 截断太狠、节点漏写、全表没列、评语没兜底、误报没标注。**修内容比修结构重要**。 ### 2. 不要改运行中的数据 真实会话在跑时,`#flush` 会覆盖 `graph.json`。**数据层回洗(降级假阳性)会被覆盖** —— 实测:降级 5 条后立刻被覆盖。 **安全做法**:在**渲染层**做标记(`[text:?]`),让消费者自己判断。 ### 3. SGF 是树,我们是 DAG SGF 用「复制子树」换简单(同一局面存两份);我们用「引用」换空间(同一节点只存一份,入边列出所有父)。 **缩进树只表达深度,不复制节点**。 ## 旧会话补文件 ```bash node test/build-tree.mjs ``` 从 `graph.json` 生成 `index.md` + `nodes/*.md`(不写 `raw/`,见 v1.2.4)。 ## 性能 | 规模 | 耗时 | |---|---| | 253 节点(801KB nodes + 60KB index) | **~150ms**(写文件部分) | | 2000 节点(估算) | ~1.5-2s | **只在「首次」和「fold 后」写** —— 不是每次 flush(2000 边时 4000 文件会卡事件循环)。