71 lines
5.7 KiB
Markdown
71 lines
5.7 KiB
Markdown
# 里程碑 2(ExcelParser 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 未在源码中出现 |