Files
2026Technology-Competition/docs/milestone2-excel-parser-review.md
T

71 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 里程碑 2ExcelParser Agent)评审与交付报告
- 日期:2026-08-09
- 状态:**有条件通过** → 评审发现 2 项 must-fix,已闭环修复后**通过**
- 关联文档:`docs/superpowers/plans/2026-08-08-milestone2-excel-parser.md``docs/design.md`(§3.5/§9.4
## 一、交付内容
新实现 8 个任务、39+2 个测试用例(当前全量 **41 passed**),12 个提交:
| 任务 | 提交 | 说明 |
|------|------|------|
| Task 1 ExcelParser 基础 | `df9427c` | `excel_reader.py`open_workbook/sheet_matrix)、`provenance.py`source_uri 格式 `file.xlsx#SheetName!CellRef`)、拒绝 `.xls` |
| Task 2 SheetDetector | `66753e4` | `sheet_detector.py` 名称/表头关键词三级判定 → `SheetType` |
| Task 3 Sheet 性质判定 | `4f61d24` | `sheet_nature.py``SheetNature`(TABLE/FREE_TEXT/MIXED)、`find_header_row``classify_sheet`design §3.5.2 启发式) |
| Task 4 MergeHandler+TableExtractor | `63d0c90` | `merge_fill.py`(合并单元格展开 forward_fill)、`table_extractor.py``extract_table`CellValue+Provenance |
| Task 5 FormattingDetector | `5818dd0` | `formatting_detector.py`(取消线/背景色/批注),修正 2 处 openpyxl 3.1.5 兼容问题 |
| Task 6 FreeTextExtractor | `a9cc3c9` | `free_text_extractor.py`(全空行分段 + 占位表,`extraction_method="llm_from_free_text"` |
| Task 7 ExcelParser 编排器 | `18da20d` | `excel_parser.py``ExcelParseResult` dataclass、`ExcelParser.parse` 编排全流程) |
| Task 8 真实样本集成测试 | `3307d7b` | `test_real_samples.py` 3 个端到端用例(新規開発/追加改修/自由記述) |
| 最终评审 must-fix | `eebed38` | `header_row` 接线 + `formatting` 回填(见下) |
## 二、验收结论
| 验收项 | 结论 |
|--------|------|
| 表格型解析(openpyxl 行列) | ✅ 新規開発 6 表全通过,DB定義 20 行 |
| 自由记述型解析(分段+占位表) | ✅ `extract_text_blocks` + `build_free_text_table`LLM 结构化显式延后 |
| 混合型解析(§3.5.2 各段落最优解析) | ⚠️ MIXED 折叠进纯表路径(评审跟踪#1,见「遗留记录」) |
| 合并单元格下行填充 | ✅ `forward_fill` 纵/横合并用例通过,编排器实际调用 |
| source_uri 格式 `file.xlsx#Sheet!Ref` | ✅ 用例通过 |
| `.xls` 拒绝(ValueError | ✅ 用例通过 |
| 取消率/背景色/批注保留 | ✅ 检测模块单测过 + 编排器实际回填(must-fix#2 后) |
| 每任务 pytest 全绿 | ✅ 41 passed(含 3 样本用例无 skip |
| 覆盖率 >80% | ⚠️ 未安装 pytest-cov,未产出覆盖率报告(可选增强,非阻塞) |
## 三、最终评审发现与修复(must-fix 闭环)
已过门的最终评审(里程碑级)发现 2 项 **must-fix**,均属本里程碑验收范围,已按 TDD 修复并回归:
### 1. `find_header_row` 结果未传入 `extract_table`
- **问题**:编排器 `excel_parser.py` 恒以默认 `header_row=0` 调用 `extract_table`;标题行置上(标题在首行、表头在第二行)的 Sheet 会把标题误当表头,损坏真实数据。
- **修复**:结构化路径改为 `header_row = find_header_row(filled)``<0` 时回落 0。
- **测试**`tests/test_excel_parser.py::test_parse_uses_detected_header_row`(断言 headers 取第二行真实表头)。
### 2. `cell_formatting` 死代码(`CellValue.formatting` 恒 None
- **问题**:检测模块存在且单测过,但运行时从未被编排器调用,取消率样式到不了下游消费者。
- **修复**`table_extractor.extract_table` 新增可选参数 `formatting_map: dict[(row,col), CellFormatting]``excel_parser` 遍历 `ws.iter_rows()` 构建 fmt_map 并传入。
- **测试**`tests/test_excel_parser.py::test_parse_attaches_strikethrough_formatting`(断言 `CellValue.formatting.strikethrough is True`)。
## 四、移交下个里程碑的遗留记录(deferred)
1. **MIXED 分段解析**design §3.5.2「段落分割→各段落最优解析」正式延后;本里程碑固定为「MIXED→表格路径」(追加改修样本观测确认,弱断言接受)。
2. **comments 回填契约**`CellComment.source_uri` 用物理坐标(`file#sheet!A2`),`CellValue.provenance` 用「列字母+相对数据行号」;消费方重链需做偏移换算(header_row≠0 时还需偏移)。建议给 `Provenance.row` 补注释明确「数据行号」语义。
3. **提取方法枚举同源**`extraction_method` 硬编码字符串 vs `ExtractionMethod` 枚举(§9.4.6 第 4 条);建议统一 `ExtractionMethod.OPENPYXL.value` / `LLM_FROM_FREE_TEXT.value`Task6/7 已用字符串)。
4. **theme 色忽略**`_to_rgb_hex` 对真实 theme 色(tinted)恒返 None,正式声明「仅检测显式 RGB 颜色」。
5. **sheet 命名规范**`sheet_matrix` 对空 sheet 是否产生 `[[None]]` 幽灵表,`skipped` 实际难触发 —— 留待 Parser/Impact 衔接时验证。
6. **公式双保留(§3.5.7)、多级表头扁平化、隐藏行列/密码**:均超出本里程碑边界,确认延后(样本规模内无影响)。
## 五、测试证据
- 全量:`python -m pytest`**41 passed in ~4.35s**14 基线 + 27 新增)
- 真实样本端到端:新規開発 6 表 openpyxl / 追加改修 2 表 openpyxl + 改修ポイント FREE_TEXT 1 行 / 自由記述 3 表 llm_from_free_text
- 缺陷观察:3 样本均 0 批注、无空 sheet
## 六、合规自查
- `data_models.py` 全程未改动(评审 #4 验证)
- 交流统一中文、标识符英文
- 每次修改均追加 `_AI_USAGE_LOG.md`(范式步骤:需求理解/Agent 实现/测试验证/整体迭代)
- 未上传任何客户/公司数据;API Key 未在源码中出现