docs: 里程碑2 评审与交付报告

This commit is contained in:
lhl
2026-08-09 03:25:57 +08:00
parent eebed38886
commit 81407afb5a
2 changed files with 79 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
Task 1: complete (commits 35d845f..df9427c, review clean)
Task 2: complete (commits df9427c..66753e4, review clean; fix: added (コード,MASTER) per design §3.5.1); Minor backlog: trailing newlines in excel_reader/provenance/excel_helpers/sheet_detector files, detect_sheet_type no docstring
Task 3: complete (commits 66753e4..4f61d24 + log b5bd21b, review clean); Minor backlog += sheet_nature MIXED branch/test coverage gap, empty-row threshold boundary test, max_cols based on len(row) vs effective cols
Task 4: complete (commits 4f61d24..63d0c90 + log 0051ad5, review clean); Minor backlog += merge_fill invalid min_row=0 branch, extract_table header_row out-of-range IndexError, trailing newlines in merge_fill/table_extractor, coverage gaps (empty matrix/row-start/header_row param)
Task 5: complete (commits 63d0c90..5818dd0 includes log, review clean); Minor backlog += formatting_detector: real tinted theme colors silently None (doc note: explicit RGB only), missing positive assertions for font/fill color, trailing newlines
Task 6: complete (commit a9cc3c9, review clean; impl matches plan placeholder-table design, no FreeText types needed); Minor backlog += free_text_extractor: hardcoded extraction_method string vs enum value, Provenance.row is block index not physical row (doc note)
Task 7: complete (commit 18da20d, review approved); IMPORTANT design gaps tracked -> (1) MIXED sheet collapsed to pure-table path (design 3.5.2 wants per-paragraph best-parse) — will surface in Task 8 real samples or Impact; (2) comments collected flat, CellValue.comment never attached — consumers must re-link via source_uri
FINAL: milestone2 有条件通过 -> must-fix x2 修复闭环 (eebed38, 41 passed) -> 交付报告 docs/milestone2-excel-parser-review.md; remaining deferred list documented (MIXED segmented parse, comments re-link contract, ExtractionMethod enum, theme colors, empty-sheet, formula/hidden/merged-header). Coverage report optional (pytest-cov not installed).
+71
View File
@@ -0,0 +1,71 @@
# 里程碑 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 未在源码中出现