5.7 KiB
5.7 KiB
里程碑 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)
- MIXED 分段解析:design §3.5.2「段落分割→各段落最优解析」正式延后;本里程碑固定为「MIXED→表格路径」(追加改修样本观测确认,弱断言接受)。
- comments 回填契约:
CellComment.source_uri用物理坐标(file#sheet!A2),CellValue.provenance用「列字母+相对数据行号」;消费方重链需做偏移换算(header_row≠0 时还需偏移)。建议给Provenance.row补注释明确「数据行号」语义。 - 提取方法枚举同源:
extraction_method硬编码字符串 vsExtractionMethod枚举(§9.4.6 第 4 条);建议统一ExtractionMethod.OPENPYXL.value/LLM_FROM_FREE_TEXT.value(Task6/7 已用字符串)。 - theme 色忽略:
_to_rgb_hex对真实 theme 色(tinted)恒返 None,正式声明「仅检测显式 RGB 颜色」。 - sheet 命名规范:
sheet_matrix对空 sheet 是否产生[[None]]幽灵表,skipped实际难触发 —— 留待 Parser/Impact 衔接时验证。 - 公式双保留(§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 未在源码中出现