ColorYourModel 缺陷与遗留问题清单
| 文档日期 | 2026-08-06 |
|---|---|
| 数据来源 | 30 轮迭代 journal + 10 份日报 + 代码现状核对 |
| 合计 | 23 项(P0 × 5,P1 × 8,P2 × 10),其中 P0-5 已于 2026-08-09 修复,P0-4 已于 2026-08-27 端到端验证关闭,P0-1/2/3 已于 2026-08-27 随 a7700df 修复(待真机复验后关闭) |
| 分级口径 | P0 阻塞验收 / 功能不正确 P1 影响体验或存在正确性隐患 P2 优化、清理、技术债 |
| 核对状态 | 2026-08-06 经两路独立 agent 逐条对照源码证伪,修订 2 处 blocker(P1-6、P2-6)与 3 处 major(P1-3、P1-8、P2-4) |
每条的核实等级(按静态源码可判定性):
| 等级 | 含义 | 条目 |
|---|---|---|
| ✅ 已证实 | 源码中找到直接证据 | P0-2、P1-1、P1-3、P1-4、P1-7、P1-8、P2-1、P2-2、P2-3、P2-5、P2-6、P2-7、P2-9、P2-10 |
| ⏳ 需真机 | 依赖运行时行为,静态不可判 | P0-1、P0-3、P0-4、P1-5 |
| ◐ 部分核实 | 常量确认存在,但具体数值来自运行日志 | P1-2、P2-8 |
一、P0 — 阻塞验收
P0-1 Fill 填充范围与高亮范围不一致 — 🔧 代码已修复(a7700df,2026-08-27),待真机复验
- 现象:点击填充后,实际着色面集与黄色高亮所示面集不符。HUD 证据:
fill face=517527 seg=0 → 12 filled / 1498252 highlighted ⚠️ MISMATCH。 - 根因:
seg=0是覆盖 150 万面的默认分区,因占比超阈值退化为局部半径填充,而高亮层仍按整段渲染。 - 历史:iter25–30 共 7 版修复,最新 v7(manual segment stickiness)仍标注"待用户验证",journal 无成功记录。
- 影响:直接阻塞 PRD 验收项 A4,也是产品核心价值(一键区域填色)不成立的原因。
- 修复(2026-08-27,
a7700df):fill 目标改为严格取segmentLabels[clickedFace](点击面所属分区),iter29 hover 偏好与 v5 陈旧缓存lastValidHoveredSegmentRef整体退役;颜色不再参与区域判定。回归测试commands::paint::fill_tests覆盖「同色双区域填充不得改写第一区域」等场景。 - 建议动作:在
cargo tauri dev下人工回归,读 HUD 的hover=/N filled / M highlighted字段确认是否收敛。若 v7 仍不收敛,须停止打补丁,改为重新取证。 - 状态:🔧 已修复 + 回归测试覆盖,待需求方真机复验同色双填充场景后关闭。
P0-2 hover 与 fill 的分区闸门不对称 — 🔧 结构性解决(a7700df,2026-08-27)
- 现象:
MANUAL_REGION_MAX_SHARE = 0.95只在paintFace侧生效(usePaintTool.ts:126-130 为 0.95 / 0.8 双分支),hover 高亮侧没有对应闸门 —— Viewport.tsx:1033-1039 只用WHOLE_SEGMENT_MAX_SHARE,且id >= MANUAL_SEGMENT_OFFSET被无条件豁免。 - 后果:高亮显示的范围与填充实际采纳的范围在阈值边界上必然分叉 —— 这是 P0-1 的结构性成因之一。
- 建议动作:把两侧闸门抽成同一个纯函数,hover 与 fill 共用,杜绝判据漂移。
- 状态:🔧 结构性解决:fill 目标不再消费 hover 快照(严格按点击面 label 路由),闸门分叉不再影响填充结果;hover 高亮降级为 HUD 诊断显示,不参与任何工具决策。
P0-3 陈旧 hover 缺少安全阀 — 🔧 结构性解决(a7700df,2026-08-27)
- 现象:hover 状态未及时失效时,可能对一个 150 万面的陈旧分区执行填充。
- 后果:一次误操作即污染整个模型,且撤销栈可能不足以完全回滚。
- 建议动作:填充前强制校验 hover 目标的时效性与面数上限,超限直接拒绝并提示。
- 状态:🔧 结构性解决:fill 不再读取任何 hover 状态(陈旧 hover 无法驱动填充);统一撤销/重做时间线(
history::undo/redo)覆盖 fill/erase/manual 编辑,可完整回滚。
P0-4 3MF 导出未经端到端验证 — ✅ 已验证关闭(2026-08-27)
- 现象:导出链路仅有 fixture 单测与链接验证,从未用真实 STL 在 GUI 里跑通并送入切片软件。用户明确表示"3mf 当前我都还没测试"。
- 后果:产品最终产物的正确性完全未知,PRD 验收项 A9 无法通过。
- 建议动作:用真实模型走完整链路,在 OrcaSlicer 中打开验证颜色,作为发版硬门槛。
- 验证记录(2026-08-27):真实 STL 走通完整链路——CYM 分区/种子上色 → 导出 3MF → Snapmaker Orca (U1) 导入,多耗材颜色正确显示,工艺下拉框正确出现内嵌预设
0.20 Standard @Snapmaker U1 (0.4 nozzle)。人工验收结论:"当前的3mf导出是合理的"。证据:samples/liangsheng/example01*.png(改名前为samples/梁圣/)。 - 状态:✅ 已验证关闭。书面验证协议(切片器版本/校验点清单)待补,模板见 docs/cases/TEMPLATE.md。
P0-5 STL 导入 kdtree 崩溃(球面等重合轴点)— ✅ 已修复(69a17ea,2026-08-09)
- 现象:打开
Sphere.stl(UV 球,32040 面 / 16022 唯一顶点,STL 本身合法)直接闪退。 - 根因:
load_stl→build_kdtree/build_vertex_kdtree,kiddo-4 默认BUCKET_SIZE=32,当同一分裂轴上 >32 点坐标完全相同时 panic(kiddo-4.2.1/.../construction.rs:"Too many items with the same position on one axis")。UV 球每个纬度环所有三角形共享同一 Z 轴坐标(单环数百面),远超 32。 - 修复:新增
kd_point(p, salt)按点 index 派生 ~1e-4 确定性扰动,对两棵树的入点均过该 helper;选扰动而非抬高 bucket(更密球仍会越界)。 - 验证:回归测试
kdtree_coincident_axis_no_panic(UV 球 50×320,单环 640 重合轴面)通过;cargo test --lib67 passed。 - 状态:✅ 已修复并打包,待需求方装包打开 Sphere.stl 复验不崩。
二、P1 — 影响体验或存在正确性隐患
P1-1 MANUAL_REGION_MAX_SHARE = 0.95 缺乏出处
阈值为拍脑袋取值,journal 明确标注无依据。需要产品侧给出判据,或改为基于分区数量分布的自适应策略。
P1-2 Phase4 小分区归并过激
MIN_REGION_CAP = 30 对 150 万面模型会把 13218 个区坍缩到 27 个。当前仅在前端做防御性适配,后端阈值未按模型规模自适应。
P1-3 addUpdateRange 截断全量写入
updateFaceColors 的 addUpdateRange(useMesh.ts:222)会截断 buildGeometry 的全量 .set()(useMesh.ts:164)。全库 clearUpdateRanges 0 处命中。属静默的正确性隐患。
注意:代码中已有反驳论据,修复前须先驳倒它。 useMesh.ts:183-187 的注释主张「renderer 每次上传后自动清空 updateRanges,故无需手动 clear」。若该假设成立则本条不成立。提工单前应先确认 three.js 当前版本的实际行为,否则会被以「注释已解释过」驳回。
P1-4 画笔 stroke 内叠加变深
同一面在一次拖动中被多次 mix_color,颜色累积变深。需后端引入 stroke_id + HashSet 去重,改动横跨 5 个文件,方案待确认。
P1-5 画笔 step 半径幻觉
step 衰减下实际着色半径为 radius/2,UI 显示值与实际不符,用户无法预期落笔范围。
P1-6 偏好缺少 migrate 迁移函数
修改默认值对已持久化用户完全无效(persist 会用旧值覆盖),后续任何默认值调整都无法触达存量用户。
现状须准确表述:version: 1 已存在(appStore.ts:418),缺的只是 migrate 函数。因已有版本号占位,补 migrate 的成本低于从零引入版本机制。
P1-7 snapEnabled 无 UI 开关
状态存在且已持久化,但界面上没有任何入口。iter23 明确警告:直接让它生效会导致吸附永久关闭且无法恢复。要么补 UI,要么移除该状态。
P1-8 render 阶段存在副作用写入(2 处,非 1 处)
违反 React 纯度约束,在并发模式下行为未定义:
useMesh.ts:52—geometryRef.current = geometry,位于useMemo内useMesh.ts:80—paintColorRef.current = arr,同类问题
只修第一处会遗漏第二处。另 updatedFaces 缺少越界校验(useMesh.ts:192-211 无 bounds check;仅 appStore.ts:314 有)。
三、P2 — 优化、清理与技术债
| ID | 问题 | 说明 |
|---|---|---|
| P2-1 | 后端 load_stl 空间索引未懒加载 |
iter9 提出,横跨 iter9→22 反复出现在 backlog,至今未做 |
| P2-2 | 批量 stroke IPC + 路径插值未做 | iter16 提出,可显著降低高频绘制的 IPC 开销 |
| P2-3 | segmentColorArray 冷启动开销 |
门控后首次切换分区视图需同步计算 54MB |
| P2-4 | DIAG-B / DIAG-D 诊断日志未清理 | 残留 2 处:commands/paint.rs:41,44、paint/brush.rs:16,22。DIAG-A / DIAG-C 已移除(全库 0 处命中,前端 src/ 亦为 0),清理时不要去找它们 |
| P2-5 | get_face_color 为死接口 |
定义 commands/mesh.rs:75,注册 lib.rs:24,前端 0 处调用(吸管实走 pick_color)。建议移除或接入 |
| P2-6 | MeshModel.unit 为死字段 |
model.rs:94 声明、:128 赋值 "millimeter",全库无读取点。⚠️ 原记「2 处 dead_code,含 apply_falloff」已证伪:apply_falloff 不存在于代码库(0 处命中),真实函数为 falloff_strength(brush.rs:29)且被 3 处调用,属热路径。警告条数须以 cargo build 输出为准 |
| P2-7 | :focus 交互态完全缺失 |
:hover/:disabled 已覆盖 .cym-btn(theme.css:114,117)与 .cym-toggle(:126);真正的缺口是 :focus 全库 0 处,键盘可达性不足 |
| P2-8 | README 与 CHANGELOG 严重过时(已逐行取证) | README:40「GPU 面拾取,颜色编码 ID 渲染到 RenderTarget」— 迭代 4 已换为 BVH 射线拾取;README:43「Space 平移」— 迭代 3 已换为右键拖拽;README:38「三阶段算法」— 未含后加的 SDF 分割;README:139 列出 eraser.rs — 该文件不存在(橡皮在 commands/paint.rs 内),且缺 sdf.rs/manual.rs/kdtree.rs/smart_snap.rs。CHANGELOG:71 停在 Round 7-8(实际已到迭代 30) |
| P2-9 | Viewport.tsx 达 2141 行 |
相机、拾取、套索层、高亮层、HUD 混杂单文件,重构候选 |
| P2-10 | 无 CI;前端零单测 | 所有验证靠人工触发;seg_log 写 CARGO_MANIFEST_DIR 运行时不可靠 |
四、非缺陷的固有限制(不予修复,仅需文档告知)
| 项 | 说明 |
|---|---|
| 分区边界几何锯齿 | 形态学平滑只能缓解;真正的直线级平滑需另立方案 |
| 模型有洞时射线 miss | 射线拾取的几何固有限制 |
maxZoom = 500 |
工程取值,正交投影无近裁面爆炸风险,可按需调整 |
| 吸附同侧阈值 60° | 经验值,锚定立方体角点 54.74° 并留约 5° 余量 |
| headless E2E 无法覆盖 IPC 功能 | Tauri runtime 缺失,属工具链固有约束 |
五、上线风险清单
| 风险 | 等级 | 说明 | 缓解 |
|---|---|---|---|
| 核心功能不正确 | 高 | P0-1 使"一键区域填色"这一核心价值不成立 | 修复并人工验收后方可发版 |
| 产物不可用 | 高 | P0-4 导出未验证,用户可能拿到无法使用的 3MF | 端到端真机验证设为发版硬门槛 |
| 大模型误操作 | 中 | P0-3 一次误填充污染 150 万面 | 补安全阀 + 确认撤销栈可完整回滚 |
| 文档误导 | 中 | P2-8 README 描述的功能与实际不符,新协作者会按错误前提开发 | 用本批文档替换 README 中过时章节 |
| 回归无护栏 | 中 | 无 CI、前端零单测,改动全靠人工回归 | 至少为 P0 相关路径补前端单测 |
六、建议的修复顺序
第一梯队(发版前必须完成)
P0-2 统一 hover/fill 闸门 ──► P0-1 验证 Fill 收敛 ──► P0-3 补安全阀
│
▼
P0-4 3MF 端到端验证
第二梯队(发版后首个迭代)
P1-3 修 addUpdateRange P1-8 移除 render 副作用 P1-6 偏好版本迁移
P2-8 同步 README/CHANGELOG
第三梯队(技术债专项)
P1-4 stroke 去重 P1-1/P1-2 阈值自适应 P2-9 Viewport 拆分 P2-10 建 CI
排序依据:P0-2 是 P0-1 的结构性成因,先统一闸门再验证填充才有意义;P0-4 独立于前三项,可并行推进。
七、本轮已收口(2026-08-07)
| 项 | 类型 | 处置 |
|---|---|---|
分区入口三处硬编码 30.0(Toolbar.tsx:89,105 + useTauriCommand.ts:41) |
技术债 / 魔法数 | ✅ 已收口:导入后自动分区改走 autoSegmentV2(buildAlgorithm(持久化 or 默认 dihedral 30°, 参数));旧 autoSegment / autoSegmentSmart 钩子退役,统一 auto_segment_v2 IPC。阈值 30° 不再来自字面量,而来自 DEFAULT_ALGORITHM_PARAMS / 持久化偏好(值与旧行为一致,仅来源变更) |
| 智能分区无统一前端入口 | 能力缺口 | ✅ 已补:新增 IntelligentSegmentPanel(模态),算法 <select> + 动态参数滑块,运行即 invoke("auto_segment_v2");选择持久化(zustand persist 白名单 + sanitizeAlgorithmParams 值域校验) |
| 后端可配置多算法分割(golden 验收) | 能力缺口 | ✅ 已落地(b087c3c):统一接口 SegmentationAlgorithm + run_segmentation + 曲率 K-Means / 形态直径 SDF / 二面角;golden 拓扑断言 74 passed(cube→6、sphere→1、双球→2)。视觉/交互仍待 cargo tauri dev 真机复验(headless 无法覆盖 Tauri 渲染) |
八、填充路由区域权威化(2026-08-27)
已修(本轮提交)
现象:已分区模型上,填充工具给区域 A 涂红后再给区域 C 涂同一种红,出现"C 变红、A 变其他色"的互斥表现。
审计结论:后端链路(segment_faces / flood_fill / apply_paint 单一写路径)全程按 segment_labels 选面,从未以颜色反推分区;问题出在前端填充目标的裁决链:
| 根因 | 位置 | 修复 |
|---|---|---|
| iter29 "hover 偏好":点击目标优先取 hover 快照而非点击面自身 label,边界处射线差一个面就填到别的区 | usePaintTool.ts Fill 分支 |
填充目标恒为 segmentLabels[clickedFace](区域信息为准) |
iter29 v5 陈旧缓存兜底:store hover 为 null 时回退到上一帧缓存的 lastValidHoveredSegmentRef,光标已离开该区仍可能被当作目标 |
Viewport.tsx enqueuePaint + pointermove/leave 写入点 |
缓存整个删除;hover 快照仅作 HUD 诊断 |
回归护栏:commands/paint.rs::fill_tests —— 同色双区域填充不得改写第一区域的任何字节;flood 路由在两侧同色时仍止步于 label 边界。
待裁决(新增 backlog,P2)
| 项 | 说明 |
|---|---|
| 分区操作用调色板色整片覆盖用户涂色 | fuse.rs:469、seeded.rs:339、manual.rs:559 均执行 face_colors[f] = manual_label_color(label),fuse/grow/lasso 会吃掉用户已有涂色。与"区域信息一直在、涂色不被破坏"的目标相悖。解法方向:算法只写 label,显示层统一走 segmentView 的 label→调色板映射,3MF 导出对未涂色面取默认色或分区代表色。改动涉及导出取色策略,需需求方拍板后再动 |