ColorYourModel logoColorYourModel Docs
GitHub ↗

ColorYourModel — 通往「可用 v0.1」路线图 · Backlog(对抗证伪快照)

文档日期 2026-08-06
状态 PAUSED(已证伪,待 REVISE) — 用户断网前要求先记录 backlog
方法 Adversarial Development Loop:PLAN(候选路线图)→ REFUTE(独立子 agent 证伪)→ [REVISE 未做]
当前分支 feat_theme_persist_paint_ux
候选路线图 见文末附录 A
证伪结论 7 个 [blocker] + 6 个 [major] + 5 个 [minor],路线图不能作为 v0.1 可靠路径
实测基线 npx tsc --noEmit exit 0 ✅;cargo test --lib 13 passed(全在 segment::manual 8 + segment::sdf 5,export/paint/mesh/commands 零覆盖);git tag -l 空(README 称 v0.1 已完成但无 tag 支撑)

⚠️ 本文件是「继续开发」的接棒点。恢复时从 §0 五个待裁决项 与 §2 修正后顺序 开工,不要从被推翻的候选路线图续。


一、五个必须先行裁决的产品/PRD 项(不裁决则后续全部不可达)

ID 裁决内容 关联 blocker 现状
D1 FR-PNT-03:Fill 目标优先取 hover,还是高亮跟随 click 命中分区? B5 / P0-3 未决。若改 click 权威,则删 lastValidHoveredSegmentRef 整条通路,P0-3 与 B4 一并根治
D2 PRD 待确认 #1:默认大分区(如 seg=0 占 150 万面)上 Fill 的期望语义(整段填充 / 半径降级 / 禁用提示) B2 / A4 未决。不裁决则 A4 字面判据「所填==高亮」按降级路径必挂
D3 PRD 待确认 #3:A9 验收基线切片软件(OrcaSlicer / BambuStudio / PrusaSlicer 选哪个矩阵) B6 / A9 未决。不裁决 A9 无判据
D4 PRD 待确认 #5:分区合并/拆分优先级是否高于 P0 修复 M4 未决(路线图误写成「明确排除」,实为待确认)
D5 手动区豁免统一到「无条件豁免」还是「≤0.95 上限」 M1-1 未决。这是产品决策不是重构

同步动作(M3):在裁决/任何代码改动前,先改 README.md 三行错误前提,否则后续 REFUTE 会按错前提取证:

  • README.md:40「GPU 面拾取:颜色编码 ID 渲染到 RenderTarget」→ 实际 iter4 已换射线拾取(FR-VIEW-07 明令禁止 GPU 回读)
  • README.md:250 [x] v0.1 — ... + 3MF 导出 → A9 从未验证,且这是仓库第一个 tag
  • README.md:251 [x] v0.2 — GPU 拾取 → 同上失真

二、修正后的开发顺序(取代被推翻的候选路线图)

Phase -1  裁决门(D1–D5 + 改 README 三行)— 必须先于任何代码改动,书面结论进 journal
Phase 0   三线并行,全部不依赖 P0 修复
  0a 校准仪器 (B1):HUD highlighted 改为与渲染同源取值,增打 renderedHover= / fillTarget= 两字段
  0b A9 前置   (B6):补 export::threemf 单测导出 XML 逐条对规范;最小 STL 真机导出送切片软件
  0c A6 前置   (B7):150 万面 + Fill 大分区,实测 10 次撤销/重做的内存与 IPC 耗时
  EXIT:0a 通过前,任何 Fill 相关读数一律不采信
Phase 1   P0-2 统一闸门(签名至少 (segId, segments, total);同时统一 v7 sticky — fill 侧无对应物)
Phase 2   P0-1 复验(在校准后的仪器上)+ 按 D2 结论重写 A4 判据
Phase 3   P0-3:按 D1 — 若判 click 权威则删 lastValidHoveredSegmentRef(根治);若判保留 hover 优先,先修 B4 永久钉死再做安全阀
Phase 4   A9 收口(0b 已排格式风险,此处做真实模型规模验证)
Phase 5   收口 + 打 tag v0.1.0(注意是仓库第一个 tag)

B3(NSIS 构建)在 journal 已多次成功(低风险),应归入「每次提交必跑」例行项,不与 A9 捆绑(M6)。


三、[blocker] 级发现(必须解决,附 file:line)

B1 — Phase 0 的判据仪器(HUD)与屏幕不同源,六次"决定性证据"全是仪器读数

  • HUD highlighted:Viewport.tsx:1183 ← facesBySeg.get(targetLbl).length,targetLbl = opts.hoveredSegment ?? clickedLbl(:1182)
  • 屏幕黄色高亮:Viewport.tsx:1786 条件 hoveredSegment !== null && !giantSegmentIds.has(hoveredSegment),渲染源是 store 的 hoveredSegment(:1788)
  • 三重分叉:① HUD 用 targetLbl(含 click 回退 + lastValidHoveredSegmentRef 复活值),屏幕用 store 值;② HUD 不过 giantSegmentIds,屏幕过;③ hover=null 时屏幕渲染 0 面,HUD 报 clickedLbl 全量。
  • 推论:journal 六条 seg=0(click) 读数意味着 store hoveredSegment 恒为 null → :1786 高亮组件根本没渲染 → 屏幕高亮面数=0 不是 1498252;且主诉是"Fill > 高亮"(溢出),HUD 数据 12 << 1498252 方向相反。七版修复建立在自相矛盾的读数上。
  • whole-segment 路径下 HUD 是同义反复:后端返回该 label 全部面,HUD 再拿 facesBySeg.get(同 label) 比 → 恒 ✓,测不出"填的与看到的是否一致";陈旧 hover 填错区时给假 ✓。
  • 违反 C3「取证优先于修改」。修正:Phase 0 前插 iter31a 校准仪器。

B2 — 闸门统一后 A4 按字面判据仍必挂(隐性 blocker)

点 seg=0(share≈1.0):hover 侧 giant→不高亮→0 面;fill 侧降级 fill_paint(radius)(usePaintTool.ts:146-150)→12 面;12≠0→仍 MISMATCH。降级是 FR-PNT-02 有意设计,闸门统一只让"决策一致"≠"面集一致"。叠加 D2 未决 → "整段填充"语义未定义。

B3 — 顺序与 docs/04 既有结论冲突且两出口都错

docs/04:128 顺序 P0-2→P0-1→P0-3,docs/04:139 明写「P0-2 是 P0-1 结构性成因」。候选路线图 Phase0=验 P0-1、Phase1=P0-2 顺序颠倒且未说明为何推翻。两 EXIT 都失效:收敛只证"这次没降级";不收敛极可能是 B1 假阳性。

B4 — v7 sticky 引入"永久 hover 钉死"活体缺陷

  • Viewport.tsx:1477 let nextHover = prevHover(miss 时不清)
  • Viewport.tsx:1484 if (!(prevIsManual && lbl < MANUAL_SEGMENT_OFFSET)) nextHover = lbl — manual 入驻后任何 auto 段永远无法覆写
  • 唯一清除点::1585(pointerleave)与 :1328(切套索);fill 优先取 hover(usePaintTool.ts:107)
  • → 用户 hover 过一次手动区后,只要指针不离开画布,之后在模型任意位置点 Fill 都填那个手动区。Phase 0 回归脚本必须含反例:hover 手动区 A → 移到模型另一端 auto 区 B → 点 Fill,预期填 B,实测填 A。

B5 — P0-3 把治标当治本,根治会撞 PRD 铁律

  • fill 取 hover:usePaintTool.ts:107 const label = (hovered != null) ? hovered : (md?.segmentLabels?.[faceId] ?? undefined)
  • 陈旧 hover 是刻意实现:Viewport.tsx:1236-1237 hoveredSegment: snap ?? lastValidHoveredSegmentRef.current — store 空时主动复活历史值(iter29 v5)
  • 在此加 TTL 安全阀三重无效:① pointermove 不记时间戳,TTL 无基准;② "面数上限"是第三套闸门,与 P0-2 要统一的两套再次分叉;③ 修不了 B4(钉死的是"新鲜"值)。
  • 根治:fill 改以 click 命中面的 segment 为准,删 lastValidHoveredSegmentRef 整条通路。但与 FR-PNT-03 冲突 → 属 PRD 级变更,须先裁决 D1。

B6 — 3MF 不兼容风险源码级已可判定,绝不能等到 Phase 4

src-tauri/src/export/threemf.rs:

  • :84 m:basematerials、:95 m:base 属核心规范默认命名空间,不属 Materials 扩展(xmlns:m)
  • :112 ("m:basematerials","1") 两规范都不存在此属性;核心规范用 pid/pindex
  • :149-150 三角形 pid="1" p1="..." 引用的 resource id=1 因上条未注册成功 → 悬空引用
  • <build><item objectid="2"/>(:174-185)存在 → 几何体会显示,颜色极可能整体丢失或报错。
  • export 模块零单测(docs/04 称"fixture 单测"不准确,实际一个都没有)。修正:A9 前移并行,先补单测打 XML 对规范逐条比。

B7 — A6 从未在目标规模验证,P0-3 前提不成立

  • 快照:Viewport.tsx:1351-1354 pushUndo(...) 每次 pointerdown 同步执行;150 万面→单次快照 ≈12MB,栈上限 appStore.ts:343 slice(-19)→20 层→常驻约 240MB
  • 回滚 IPC:useTauriCommand.ts:189 → 后端 restore_face_colors(segment.rs:272-276),Tauri 把两数组序列化为 JSON 数字数组 → 单次撤销传 600 万+150 万个十进制数;A6 要求 10 次撤销+重做=20 次往返
  • P0-3 立论("撤销栈可能不足以完全回滚")依赖 A6,而 A6 本身可能是独立 blocker。A6 必须与 Phase 0 并行验证,用例须 150 万面 + Fill 大分区。

四、[major] 级发现

M1 — 闸门不对称真实存在,但候选方案描述与签名都错

维度 hover giantSegmentIds(Viewport.tsx:1028-1040) fill fillWholeSegment(usePaintTool.ts:125-130)
人口 autoSegs = segs.filter(id<100000)(:1033) realSegs = segs.filter(faceCount>0)(:122)含手动区
数量分支 autoSegs.length<=1→静音全部 auto(:1034-1036) realSegs.length>1 才允许整段(:129)
占比阈值 faceCount > total*0.8(:1038-1039) share <= 0.8(:129)
手动区 id>=100000 无条件豁免(:1033/:1039) 豁免但受 0.95 上限(:128)
额外闸门 v7 sticky !(prevIsManual && lbl<100000)(:1484) 无对应物
常量可见性 仅 WHOLE_SEGMENT_MAX_SHARE、MANUAL_SEGMENT_OFFSET(:7) MANUAL_REGION_MAX_SHARE 仅 usePaintTool.ts:16/128
  • M1-1:手动区豁免两侧语义不同(hover 无条件 / fill ≤0.95)→ 统一到哪侧是产品决策(D5)。
  • M1-2:拟议签名 shouldWholeSegmentFill(segId, share) 表达不足——autoSegs.length<=1 与 realSegs.length>1 需完整 segments 列表,至少需 (segId, segments, total);否则会静默丢掉数量分支制造新不对称。
  • M1-3(docs/04-P0-2 未记载的第三处不对称):autoSegs.length<=1 vs realSegs.length>1。反例:1 auto + 2 manual → hover 静音该 auto(length=1),fill 却允许整段(length=3)→ 填 N 面/高亮 0 面。
  • M1-4:REFUTE 目标应改为"同一 (segId, segments, total) 输入下返回同一布尔值",非"字节一致"。

M2 — P1-6 应写成条件门,非无条件放 Phase 6

appStore.ts:418 version:1 无 migrate 属实;:435 merge: mergePrefs、:124-126 范围校验、:198 clamp 已在 → FR-PRF-04 满足。真风险:Phase1 若把 0.8/0.95 做成偏好项或 Phase3 安全阀阈值进 partialize,存量用户升级后旧值覆盖新默认 → A7 表面过但行为回退。⚠️ 反论据::110-115 B1 注释明写「不要用 migrate」——仅针对 legacy cym-theme 键,补 migrate 前须在 journal 限定该注释范围(同类 P1-3 陷阱)。条件门:若 v0.1 未改 partialize 8 项默认值→留 Phase6;一旦触碰→升级为发版前必做。

M3 — P2-8 放 Phase 5 让 v0.1 定义自相矛盾且自伤

见 §一 D 同步动作(README:40/:250/:251)。另:CHANGELOG 实际停在 Round 3-4,docs/04:94 记"Round 7-8"清单自身也漂。

M4 — 排除项与 PRD 待确认 #5 冲突,状态标错

路线图写「明确排除 v0.1」把 PRD:198 待确认写成已决。改两栏:「已确认排除:调色板历史 / 批量处理 / OrcaSlicer 插件形态集成」/「待用户确认排除:分区合并/拆分(PRD 待确认 #5)」。

M5 — Phase 1 是同一思路第 8 次,C3 铁律被架空

iter25-30 已 7 轮同思路(追 hoveredSegment 传递链路)变体。必须显式写明"换角度":(i) 放弃 hover 优先改 click 权威(B5);或 (ii) 后端返回本次实际填充面集,前端用同一面集渲染高亮,从根消灭"两个面集"概念。

M6 — Phase 4 把 A9 与 B3 捆绑,失败模式不同

B3(NSIS)已多次成功低风险;A9 零验证零单测源码级已见格式问题。B3 归「每次提交必跑」例行项,A9 单独立项前移。


五、[minor] 级

  • m1 行号漂移:闸门实际 Viewport.tsx:1028-1040,只引 1033-1039 漏掉 autoSegs.length<=1 早退(:1034-1036),正是 M1-3 所在。
  • m2 「P0-1 最终收敛」预设结论,违反 C3 精神,改中性「P0-1 复验」。
  • m3 P2-8 README同步 同时出现在 Phase5 与 Phase6,职责不清。
  • m4 「cargo test 13」须加限定:全在 manual(8)+sdf(5),paint/export/mesh/commands 0 覆盖,当工程护栏会高估强度。
  • m5 排除项「OrcaSlicer 插件」与 A9「产物在 OrcaSlicer 打开」措辞近易误读,改「OrcaSlicer 插件形态集成(不影响 A9 导出兼容性验证)」。

六、恢复开发时的下一步(REVISE 阶段)

  1. 与用户确认 D1–D5 五个裁决项(最可能是一次对话/留言敲定)。
  2. 按裁决改 README.md 三行(M3),提交。
  3. 派 REFUTE 重做 iter31a 仪器校准方案(B1),确保 HUD 与渲染同源。
  4. 按 §二顺序逐 Phase 走完 PLAN→REFUTE→REVISE→IMPLEMENT→TEST→RETROSPECT,每轮追加 loop-journal 条目。
  5. 同步把状态回填到项目「计划」待办(P0-2/P0-3/P0-4 + 新增 A6/A9 前置 + README 校正),断网恢复后再用 wb-issues 工具同步。

附录 A — 被证伪的候选路线图(原始)

定义"可用 v0.1"门槛 = PRD §6.1 A1–A9 全过 + §6.2 B1–B3。
4 个 P0 必须清零:A4(Fill一致性)、A9(3MF E2E)、P0-2(闸门不对称)、P0-3(陈旧hover安全阀)。
Phase 0 验证闸门(iter31):真机回归 iter30 v7 ... EXIT 收敛→A4过 / 不收敛→重新取证
Phase 1 P0-2 统一闸门(iter32):抽纯函数 shouldWholeSegmentFill(segId,share) 供 hover/fill 共用
Phase 2 P0-1 最终收敛(iter33)
Phase 3 P0-3 陈旧 hover 安全阀 + A6 撤销(iter34)
Phase 4 P0-4 3MF E2E(iter35):导出→OrcaSlicer验色 + NSIS安装包
Phase 5 收口:打 tag v0.1.0;校正 README/CHANGELOG/PRD
Phase 6(发版后) P1-3/P1-8/P1-6/P1-7/P2-8
Phase 7(技术债) P1-4/P1-1/2/P2-9/P2-10
明确排除:选区合并/拆分、调色板历史、批量处理、OrcaSlicer 插件
On this page