refactor(panels): 删除 rowPoints/rowIterations 死列 + 提取 PaintPanelResampleRows

对应 Code_Review_Report §14.5 第 1 项与第 3 项。

第 1 项:删除 EdgePanelLayout::rowPoints / rowIterations(行数组 18 → 16)
- 写入方只有 AppendRow(推空矩形),读取方只有调试框 AddAll 与 PanelSlotKey 的 mix 循环,
  绘制方零(旧式“点数 / 迭代次数”输入框早被滑块版 rowLevelTracks / rowIterTracks 取代)。
- 连带同步:AppendRow、调试框、缓存键、rowgeom 导出、panels/panelscroll 长度不变式、
  文档里的列数(18/14 → 16/12)。

等价性由基线证伪,而不是靠人工 grep:
  old lines = 983, new lines = 919
  only in OLD = 64, only in NEW = 0
  only-in-OLD lines NOT belonging to rowPoints/rowIterations = 0
即除被删两列外,其余 919 条键逐字节相同。

第 3 项(前半):提取 PlotView::PaintPanelResampleRows
- PaintPanelListRows 里 `if (resamplePanel) { …; continue; }` 共 132 行整块提取,
  签名 (g, layout, rowIndex, laneIndex, ref, item);两个局部 lambda
  (paintInfoRow 只读统计行 / paintInputRow 联动输入框)随之迁移。
- maxInterval / minInterval 两个纯拷贝局部量直接用 item.maxInterval / item.minInterval。
- 通用参数行(中心轴统计 + 两行滑块)未提取:需 9 个参数,签名比函数体更难读。

§14.5 第 2 项(完整结构合并)本轮不做,方案已定并写入文档:
- 列视图(PanelColumn<T>)方案否决:拷贝忘重绑 = 静默悬垂,需额外自检兜住;
- 若要做就做“vector<PanelRow> + 具名成员访问(无视图)”,242 处读点(127 处命中判定),
  必须单独一轮。它属整洁性收益(漏推一列已被 AppendRow + 长度不变式挡住),不是紧急项。

验证
- make release:零 warning;785,408 → 784,896 B(−512);make debug 同样零 warning
- make -C Tools:零 warning
- UnitTests:checks=260 failed=0 cases=19
- OffscreenChecks -all:7 检查 / 127 断言全 PASS
- panels -mode compare:7 面板像素哈希 + 几何逐项不变(resample=2BFC74B3D9B3239C)
- rowgeom -mode compare:919 + 7 键,0 差异(基线已按 16 列重录)
- PlotViewPaint.cpp 5575 → 5565;PlotViewPanelPaint.cpp 1016 → 1020

文档:Plan §十、Progress 第 38 轮、Report §15、agent_mem 第 38 轮、Tools/README §4.4
This commit is contained in:
DeepSeek V4.1 Flash committed 2026-11-04 16:02:15 +08:00
1 parent 353c553721
commit f07ac74988
9 files changed
+384 -150

No files matched your search

+36
View File
@@ -307,3 +307,39 @@
`SetAllVisible(false)`,而"全部不可见 ⇒ 丢弃网格"是既有设计
(`RebuildLanes` 的 MERGED 分支),固定点/面板开关会随之清空 —— 该场景要**重新播**。
---
## 十、第 38 轮追加(2026-11-04):§14.5 第 1 项(删死列)+ 第 3 项前半(拆重采样行)
> 触发:用户要求「按照上一轮报告中的 §14.5 下一步(按价值排序)继续推进」。
| 节点 | 内容 | 验收标准 |
| --- | --- | --- |
| **P31** | 删除 `EdgePanelLayout::rowPoints` / `rowIterations`(写入方只剩 `AppendRow`,读取方只剩调试框与缓存键,几何恒为空) | `rowgeom -mode compare` 的差异**只**来自这两列(64 条键,0 条其它差异);`panels -mode compare` 像素不变 |
| **P32** | 从 `PaintPanelListRows` 提取 `PaintPanelResampleRows`("四行只读统计 + 联动输入框"这一段) | 面板像素哈希(尤其 `resample`)与逐行几何**逐项不变** |
### 10.1 为什么"删掉一列"也可以证明
`rowgeom` 的两层基线正好给出**可证伪**的等价性:
* 旧基线 983 行、新基线 919 行;集合差 = 只在旧里的 **64** 行、只在新里的 **0** 行;
* 那 64 行**全部**属于 `rowPoints` / `rowIterations`(脚本按正则断言,非人工核对);
* ⇒ 其余 919 条键**逐字节相同**,也就是说"删掉的两列从没被赋予过非空矩形"这一判断被基线证实。
### 10.2 本轮新增硬约束
1. **`EdgePanelLayout` 行相关的平行数组现在是 16 个**(原 18)。任何"列清单"
(`rowgeom` 导出、长度不变式、调试框、缓存键)都要同步;`AppendRow` 里少推一列
仍会被长度不变式当场抓到。
2. **只读统计/输入框这类"专属排版"要独立成函数**:`PaintPanelResampleRows` 的四行
与其它面板的滑块参数行没有共同点,混在同一个行循环里只会让三种排版互相纠缠。
3. **§14.5 第 2 项(完整结构合并)仍处于"闸门关闭"状态**,未做(理由见 Report §15.3)。
### 10.3 §14.5 第 3 项的完成度
| 段落 | 状态 |
| --- | --- |
| 重采样行(四行只读+输入) | ✅ 已提取为 `PaintPanelResampleRows` |
| 通用参数行(中心轴统计 + 两行滑块) | ⏸ 未提取:依赖 3 个 kind 标志 + 2 套拖拽/编辑状态 + 2 个滑块 lambda,提取需传 9 个参数,可读性收益低于参数表本身 |
| 条目栏(三角 + 名称 + 复选框 + 悬停) | 保留在 `PaintPanelListRows` 里(它是三种排版的公共前缀) |
+59
View File
@@ -491,3 +491,62 @@ SUMMARY checks=32 failed=1 groups=1 result=FAIL
| `rowgeom -mode compare -data MF4-Record.MF4` | `detail 1304 键 + scale 7 键`(566 行),0 差异 |
| `panels -mode compare` | 7 个面板像素哈希 + 几何逐项不变 |
---
## 第 38 轮(2026-11-04):删死列 + 拆重采样参数行(§14.5 第 1 / 第 3 项)
### P31 删除 `rowPoints` / `rowIterations` —— ✅ 完成
审计(§14.5 第 1 项的前提)在三处确认它们是**死列**:
| 位置 | 原用途 | 现状 |
| --- | --- | --- |
| 写入 | `AppendRow` 里推两个空矩形 | 这是**唯一**写入点,从未被赋过非空矩形 |
| 读取 | `PlotViewPaint.cpp` 调试框 `AddAll`、`PanelSlotKey` 的 mix 循环 | 都是"遍历即忘",不产生任何可见效果 |
| 绘制 | 无 | 旧式"点数 / 迭代次数"输入框早被滑块版(`rowLevelTracks` / `rowIterTracks`)取代 |
改动:删两个 `std::vector<gd::RectF>`(`EdgePanelLayout` 少 48 字节)、`AppendRow` 少两次 `push_back`、
调试框与缓存键各少两个循环、`rowgeom` 导出与两处长度不变式各少两项(16 列)。
**等价性被基线证明**(这是本轮最值得记的一条方法论):
```text
old lines = 983, new lines = 919
only in OLD = 64, only in NEW = 0
only-in-OLD lines NOT belonging to rowPoints/rowIterations = 0
```
* 983 − 919 = 64,正好是两列在 7 个面板上的键数(`count` 键 + 每行键);
* 其余 919 条键**逐字节相同** ⇒ "这两列从未有非空值"的判断不是靠眼睛,而是靠基线证伪。
* 随后用新代码重新 `record` 正式基线(`rowgeom-baseline.txt`),再次 `compare` 归零。
### P32 提取 `PaintPanelResampleRows` —— ✅ 完成
`PaintPanelListRows` 里 `if (resamplePanel) { …四行… continue; }` 这 **132 行**整块提取为
`PlotView::PaintPanelResampleRows(g, layout, rowIndex, laneIndex, ref, item)`:
* 两个局部 lambda(`paintInfoRow` 只读统计行 / `paintInputRow` 联动输入框)随之迁移;
* `maxInterval` / `minInterval` 两个"拷贝一份再说"的局部量直接用 `item.maxInterval` /
`item.minInterval`(原来是纯拷贝,无语义差别);
* 调用点只剩 3 行(含注释),`PaintPanelListRows` 现在只有"条目栏 + 通用参数行"两段。
### §14.5 第 3 项的完成度(诚实记录)
| 段落 | 状态 | 理由 |
| --- | --- | --- |
| 重采样行 | ✅ 已提取 | 排版与其它面板完全不同、入口/出口干净(`continue` 收尾) |
| 通用参数行(中心轴统计 + 两行滑块) | ⏸ 未提取 | 依赖 3 个 kind 标志 + 2 套状态(`m_dragMode`/`m_editTarget`)+ 2 个滑块 lambda,签名要约 9 个参数,可读性收益低于参数表成本 |
| 条目栏 | 保留 | 三角 + 名称 + 复选框 + 悬停是三种排版的公共前缀 |
### 本轮验证
| 项 | 结果 |
| --- | --- |
| `make release`(全量) | 零 error / 零 warning;产物 785,408 → **784,896 B**(−512) |
| `make -C Tools` | 零 error / 零 warning |
| `UnitTests` | `checks=260 failed=0 cases=19` |
| `OffscreenChecks -all` | 7/7 PASS,`checks=127 failed=0` |
| `panels -mode compare` | 7 个面板像素哈希 + 几何**逐项不变**(含 `resample=2BFC74B3D9B3239C`) |
| `rowgeom -mode compare` | 919 + 7 键,0 差异 |
| 行数 | `PlotViewPaint.cpp` 5575 → 5565;`PlotViewPanelPaint.cpp` 1016 → 1020(净增 4 行:函数头 + 文档) |
+73
View File
@@ -610,3 +610,76 @@ Tools/README.md 目录结构、作用、测试项、验收标准、A/B
否则不建议动。
3. `PaintPanelListRows` 再拆三段(纯可读性)。
---
## 十五、第 38 轮:§14.5 第 1 / 第 3 项
### 15.1 结论
| §14.5 建议 | 结果 |
| --- | --- |
| 1. `rowPoints` / `rowIterations` 清理 | ✅ 删除(`EdgePanelLayout` 16 列),产物 −512 B,基线证明等价 |
| 2. 完整结构合并(`vector<PanelRow>` + 列视图) | ⏸ **未做**,闸门仍关闭(理由见 §15.3) |
| 3. `PaintPanelListRows` 再拆 | ◑ 重采样行已提取(132 行),参数行未提取(理由见 §15.4) |
### 15.2 "删掉一列"的等价性怎么证明
`rowgeom` 让"删除死列"从"我看过没人用"变成**可验证**:
```text
old lines = 983, new lines = 919
only in OLD = 64, only in NEW = 0
only-in-OLD lines NOT belonging to rowPoints/rowIterations = 0
```
* 唯一差异就是被删两列的 64 条键;其余 919 条**逐字节相同**;
* 因为 `rowgeom` 导出的是**每个矩形的每个字段**,"这两列恒为空"这一前提被直接证伪/证实,
不依赖人工 grep 的完整性。
这给出一条可复用的方法:**先有全字段基线,再删字段**;否则"删掉的东西没人用"永远只是断言。
### 15.3 为什么 §14.5 第 2 项仍然不做
报告本人的判据是"若要做,必须同时给 `EdgePanelLayout` 加视图自检,否则不建议动"。
本轮把这一步的门槛量化了:
| 方案 | 改动面 | 失败可见性 |
| --- | --- | --- |
| A:`std::vector<PanelRow>` + 列视图(`PanelColumn<T>`) | 242 处读点(其中 **127** 处在 `PlotViewInteraction.cpp` 的命中判定里)+ 自定义拷贝/赋值 + 视图自检 | 拷贝后忘重绑 = **静默悬垂**,只能靠新增自检兜住 |
| B:`std::vector<PanelRow>` + 具名成员访问(无视图) | 同样是 242 处,但所有访问变成 `rows[i].check`,**结构上不可能悬垂** | 编译期全查;无新风险 |
> 结论:真要做就做 **B**(无视图),A 的"零改动读点"是幻觉 —— 省下的正则改写换来一个
> 必须靠新自检才能发现的隐患。B 的代价是 242 处机械替换(含 30 余处 range-for 与 `.size()`),
> 适合单独一轮、以 `rowgeom` + `panels` 双基线为判据,而不是塞在本轮末尾。
另外现在"漏推一列"已被 `AppendRow` + 长度不变式双重挡住,
B 的**剩余收益**主要是"单一分配 + 少 15 个 vector 头"(`EdgePanelLayout` 每实例省约 360 B
头部,566 个网格时约 200 KB,但那是**布局对象**、每帧临时构造,实际峰值影响很小)。
因此 B 的优先级应低于"面板结构再简化"的实际痛点,属于**整洁性收益**而非正确性收益。
### 15.4 §14.5 第 3 项的取舍
| 段落 | 状态 |
| --- | --- |
| 重采样行(132 行:两行只读统计 + 两行联动输入框) | ✅ 提取为 `PaintPanelResampleRows`,零逻辑改动 |
| 通用参数行(中心轴统计 + 两行滑块) | ⏸ 提取需 9 个参数(`layout`/`rowIndex`/`laneIndex`/`ref`/`kind`/`resolved`/`item`/`peakItem`/`tabLane`),签名比函数体更难读 |
| 条目栏 | 保留(三种排版的公共前缀) |
### 15.5 验证
| 项 | 结果 |
| --- | --- |
| `make release` | 零 warning;**784,896 B**(−512) |
| `UnitTests` | 260 / 19 PASS |
| `OffscreenChecks -all` | 7 / 127 PASS |
| `panels -mode compare` | 7 面板像素哈希逐项不变 |
| `rowgeom -mode compare` | 919 + 7 键,0 差异 |
### 15.6 下一步(更新)
1. **方案 B(`vector<PanelRow>` 无视图)单独一轮**:判据 = 编译通过 + `rowgeom`/`panels` 双基线归零;
预期收益是"字段重载(`rowRefs` 双语义)"这类问题从**结构上消失** —— 这比省字节更重要。
2. 若要在 B 之上再做**语义化**:把 `rowRefs` 的双语义拆成 `rows[].ref` + `markerGroups[]`,
让"MARK 面板 12 列为空"的注释消失。
3. 面板几何算式重写(§13.6 遗留):基线已就绪,但需先完成 1 或 2。
+57
View File
@@ -10638,3 +10638,60 @@ MARK 面板**只填** `rowNameRects` / `rowNameCloses`,其余 14 列**必须
`EdgePanelLayout` 加"视图自检"(比对 `rows` 容量与视图长度)。
3. `PaintPanelListRows` 再拆三段(纯可读性)。
---
## 2026-11-04 · 第 38 轮(`Code_Review` 分支):删死列 + 拆重采样参数行(§14.5 第 1 / 第 3 项)
> 规则原文:`Documents/Code_Review_Report.md` §15、`Code_Review_Plan.md` §十、
> `Code_Review_Progress.md` 第 38 轮。
### 1. ✅ 删除 `EdgePanelLayout::rowPoints` / `rowIterations`(行数组 18 → **16**)
* 写入方**只有** `AppendRow`(推空矩形),读取方**只有**调试框 `AddAll` 与 `PanelSlotKey` 的 mix 循环,
绘制方零(旧式"点数 / 迭代次数"输入框早被滑块版取代)。
* 任何"面板行数组清单"现在都是 **16 列**:`rowgeom` 导出、`panels`/`panelscroll` 长度不变式、
调试框、缓存键、`AppendRow`。
### 2. ⭐ 方法论:**先有全字段基线,再删字段**
本轮"删两列"的等价性不是靠 grep 完整性,而是靠 `rowgeom` 证伪:
```text
old lines = 983, new lines = 919 ; only in OLD = 64 ; only in NEW = 0
only-in-OLD lines NOT belonging to rowPoints/rowIterations = 0
```
⇒ 以后删任何 `EdgePanelLayout` 字段,都走这个流程:
`record 旧 → 改代码 → record 新到独立目录 → 集合差只应包含被删字段 → 再 record 正式基线`。
### 3. ✅ 提取 `PaintPanelResampleRows`(132 行)
`PaintPanelListRows` 里 `if (resamplePanel) { …; continue; }` 整块提取;签名
`(g, layout, rowIndex, laneIndex, ref, item)`;两个局部 lambda(只读统计行 / 联动输入框)随之迁移。
**通用参数行(中心轴统计 + 两行滑块)未提取**:需 9 个参数,签名比函数体更难读。
### 4. ⛔ §14.5 第 2 项(完整结构合并)**仍未做**,且方案已定
| 方案 | 结论 |
| --- | --- |
| A:`vector<PanelRow>` + `PanelColumn<T>` 列视图 | ❌ 不做:242 处读点看似"零改动",但自定义拷贝忘重绑 = **静默悬垂**,只能靠新增自检兜住 |
| B:`vector<PanelRow>` + 具名成员访问(无视图) | ✅ 若要做就做这个:所有访问变 `rows[i].check`,**结构上不可能悬垂**,可省略自检 |
B 的规模:242 处读点(**127** 在 `PlotViewInteraction.cpp` 命中判定里)+ 30 余处 range-for / `.size()`。
**必须单独一轮**,判据 = 编译通过 + `rowgeom`/`panels` 双基线归零。
B 属**整洁性收益**(漏推一列已被 `AppendRow` + 长度不变式挡住),不是正确性收益 —— 别再当紧急项。
### 5. 本轮数字
* Release 785,408 → **784,896 B**(−512);零 warning。
* `UnitTests` 260/19;`OffscreenChecks -all` 7 检查 / 127 断言全 PASS。
* `panels -mode compare` 7 面板像素哈希逐项不变(含 `resample=2BFC74B3D9B3239C`)。
* `rowgeom -mode compare` 919 + 7 键 0 差异(基线已按 16 列重新录)。
* `PlotViewPaint.cpp` 5575 → 5565;`PlotViewPanelPaint.cpp` 1016 → 1020。
### 6. 下一步
1. 方案 B(`vector<PanelRow>` 无视图)单独一轮;顺带把 `rowRefs` 的双语义拆成
`rows[].ref` + `markerGroups[]`,让"MARK 面板 12 列为空"的注释消失。
2. 面板几何算式重写(§13.6 遗留):基线已就绪,但需先完成 1。