> **发布元数据**：ZCode · Kimi K3（评测者确认）· R01
> **来源**：`zcode/输出/zcode/T07/R01/BENCHMARK_RESULT.md`
> **原始文件 SHA-256**：`3bbc292384a811253192017152393e086324aa2dea3b6cb5e120cdcbc88cb784`
> 本公开副本已将评测机绝对路径归一化；下文 PASS/FAIL/BLOCKED 是执行报告自述状态，不等同于独立验收结论。

---

PASS

# T07 R01 基准结果：保持兼容性的重构

## 重构前后职责变化

重构前：
- `ledger/cli.py` 内部私有函数 `_parse_cli_date(value, field_name)` 用 `datetime.strptime(value, "%Y-%m-%d").date()` 解析 CLI 的 `--start-date/--end-date`，再做 `parsed.isoformat() != value` 严格比对。
- `ledger/query.py` 内部私有函数 `_parse_date_bound(value, field_name)` 用 `date.fromisoformat(value)` 解析查询边界，同样做 isoformat 严格比对。
- 两份逻辑职责重复：都把 None 映射为 None、把 TypeError/ValueError 统一转成 `ValueError(f"{field_name} must use YYYY-MM-DD")`。

重构后：
- 新增 `ledger/dates.py`，导出唯一共用实现 `parse_date_bound(value, field_name)`（None→None；非法输入→`ValueError("<field> must use YYYY-MM-DD")`；严格零填充 YYYY-MM-DD）。
- `ledger/cli.py` 删除 `_parse_cli_date` 及不再需要的 `from datetime import datetime`，`main()` 中 CLI 校验改调 `ledger.dates.parse_date_bound`。
- `ledger/query.py` 删除 `_parse_date_bound`，`filter_by_date` 改调同一实现；排他边界过滤循环（`<=`/`>=` 跳过）一行未动，冻结基线过滤语义保持不变（包含性修复属 T04，不在本题范围）。
- CLI 参数解析、数据加载、格式化、汇总等其他职责均未改动；无全仓库改名、无无关格式化。

行为等价性说明：在 Python 3.9.6 下，strptime 路径虽能解析 `2025-1-1` 这类非零填充输入，但随后的 `parsed.isoformat() != value` 比对会将其拒绝，因此两条原实现对所有输入的接受集完全一致（只接受零填充合法 YYYY-MM-DD）。共用实现采用 `date.fromisoformat` + isoformat 比对（与 query.py 原实现逐字一致），CLI 路径行为随之完全等价。

## 实际改动（均在 workspace 内，未提交，HEAD 仍为冻结提交 ed2390f2df8252f062abd9123e20f6fffca7e5ed）

1. 新增 `ledger/dates.py`：共用函数 `parse_date_bound(value, field_name)`。
2. 修改 `ledger/cli.py`：删除 `_parse_cli_date`（13 行）与 `from datetime import datetime`；新增 `from .dates import parse_date_bound`；`main()` 两处调用改为 `parse_date_bound(args.start_date, "start_date")` / `parse_date_bound(args.end_date, "end_date")`。
3. 修改 `ledger/query.py`：删除 `_parse_date_bound`（12 行）与 `from datetime import date`；新增 `from .dates import parse_date_bound`；`filter_by_date` 签名、返回类型（list）、排他过滤循环不变。
4. 新增兼容性测试 `tests/test_t07_dates.py`（10 个用例：共用解析器行为、filter_by_date 签名/返回类型/排他边界/错误消息、CLI 错误输出与退出码 2）。
5. 未删改 `tests/test_baseline.py`，未改动 `tests_t08/`、`docs/`、源数据或任何其他文件；未增加任何依赖（仅标准库）。

## 对照实验原始输出

### 重构前基线（Python 3.9.6，两份原实现 `_parse_cli_date` vs `_parse_date_bound`）

```
=== PRE-REFACTOR BASELINE ===
input='2025-01-01'         cli=('OK', 'datetime.date(2025, 1, 1)')  query=('OK', 'datetime.date(2025, 1, 1)')  [SAME]
input=None                 cli=('OK', 'None')  query=('OK', 'None')  [SAME]
input='2025-13-01'         cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-02-30'         cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='01/01/2025'         cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-1-1'           cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input=123                  cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-1-15'          cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-01-1'          cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input=''                   cli=('ValueError', 'test_field must use YYYY-MM-DD')  query=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
```

### 重构前 filter_by_date 基线

```
all: [('A-02', '2025-01-01'), ('A-01', '2025-01-01'), ('B-01', '2025-01-02'), ('C-01', '2025-01-31'), ('D-01', '2025-02-01'), ('E-01', '2024-12-31')]
start=None, end=None -> OK ['A-02', 'A-01', 'B-01', 'C-01', 'D-01', 'E-01']
start='2025-01-10', end=None -> OK ['C-01', 'D-01']
start=None, end='2025-02-01' -> OK ['A-02', 'A-01', 'B-01', 'C-01', 'E-01']
start='2025-01-10', end='2025-02-15' -> OK ['C-01', 'D-01']
start='2025-13-01', end=None -> ValueError: start_date must use YYYY-MM-DD
start=123, end=None -> ValueError: start_date must use YYYY-MM-DD
start='2025-1-1', end=None -> ValueError: start_date must use YYYY-MM-DD
signature: (transactions, start_date=None, end_date=None)
return type: <class 'list'>
```

### 重构前 CLI 基线

```
$ python3 -m ledger list --start-date 2025-13-01  ->  stderr: ledger: error: start_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --start-date 2025-1-1    ->  stderr: ledger: error: start_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --start-date not-a-date  ->  stderr: ledger: error: start_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --end-date 2025-02-30    ->  stderr: ledger: error: end_date must use YYYY-MM-DD ; exit=2
```

### 重构后共用实现 vs 基线（逐一比对）

```
=== POST-REFACTOR SHARED PARSER vs BASELINE ===
input='2025-01-01'         post=('OK', 'datetime.date(2025, 1, 1)')  expected=('OK', 'datetime.date(2025, 1, 1)')  [SAME]
input=None                 post=('OK', 'None')  expected=('OK', 'None')  [SAME]
input='2025-13-01'         post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-02-30'         post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='01/01/2025'         post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-1-1'           post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input=123                  post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-1-15'          post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input='2025-01-1'          post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
input=''                   post=('ValueError', 'test_field must use YYYY-MM-DD')  expected=('ValueError', 'test_field must use YYYY-MM-DD')  [SAME]
ALL MATCH: True
=== POST-REFACTOR filter_by_date ===
start=None, end=None -> OK ['A-02', 'A-01', 'B-01', 'C-01', 'D-01', 'E-01']
start='2025-01-10', end=None -> OK ['C-01', 'D-01']
start=None, end='2025-02-01' -> OK ['A-02', 'A-01', 'B-01', 'C-01', 'E-01']
start='2025-01-10', end='2025-02-15' -> OK ['C-01', 'D-01']
start='2025-13-01', end=None -> ValueError: start_date must use YYYY-MM-DD
start=123, end=None -> ValueError: start_date must use YYYY-MM-DD
start='2025-1-1', end=None -> ValueError: start_date must use YYYY-MM-DD
signature: (transactions, start_date=None, end_date=None)
return type: <class 'list'>
```

### 重构后 CLI

```
$ python3 -m ledger list --start-date 2025-13-01  ->  stderr: ledger: error: start_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --start-date 2025-1-1    ->  stderr: ledger: error: start_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --end-date 2025-02-30    ->  stderr: ledger: error: end_date must use YYYY-MM-DD ; exit=2
$ python3 -m ledger list --start-date 2025-01-10  ->  stdout:
C-01 | 2025-01-31 | food | $0.01
D-01 | 2025-02-01 | 家庭 | $3.50
exit=0
$ python3 -m ledger list  ->  6 行全部输出（A-02/A-01/B-01/C-01/D-01/E-01），exit=0
```

结论：重构前后所有代表性输入（合法 `"2025-01-01"`、None、`"2025-13-01"`、`"2025-02-30"`、`"01/01/2025"`、`"2025-1-1"`、`"2025-1-15"`、`"2025-01-1"`、空串、非字符串 `123`）的返回值与 ValueError 消息完全一致；filter_by_date 签名、返回类型、排他过滤结果不变；CLI 错误输出格式与退出码 2 不变。

## 实际运行的命令与结果

1. `python3 --version` → Python 3.9.6
2. 重构前 `python3 -m unittest discover -s tests -v` → 4 tests OK（基线原始输出如下）
3. 重构前/后对照实验脚本（内联 heredoc，见上方原始输出）→ 重构后 ALL MATCH: True
4. 重构前后 `python3 -m ledger list [--start-date/--end-date ...]` 多组 → stderr/exit 完全一致
5. 重构后 `python3 -m unittest discover -s tests -v` 原始输出：

```
test_default_fixture_loads (test_baseline.BaselineSmokeTests) ... ok
test_default_summary_shape (test_baseline.BaselineSmokeTests) ... ok
test_list_command_runs (test_baseline.BaselineSmokeTests) ... ok
test_valid_money_inputs (test_baseline.BaselineSmokeTests) ... ok
test_invalid_dates_print_error_and_exit_2 (test_t07_dates.CliDateCompatTests) ... ok
test_list_without_dates_unchanged (test_t07_dates.CliDateCompatTests) ... ok
test_valid_dates_still_filter (test_t07_dates.CliDateCompatTests) ... ok
test_frozen_exclusive_boundaries_unchanged (test_t07_dates.FilterByDateCompatTests) ... ok
test_invalid_bounds_raise_valueerror (test_t07_dates.FilterByDateCompatTests) ... ok
test_no_bounds_returns_everything (test_t07_dates.FilterByDateCompatTests) ... ok
test_signature_and_return_type (test_t07_dates.FilterByDateCompatTests) ... ok
test_invalid_inputs_raise_shared_message (test_t07_dates.SharedParserTests) ... ok
test_none_returns_none (test_t07_dates.SharedParserTests) ... ok
test_valid_zero_padded_date (test_t07_dates.SharedParserTests) ... ok

----------------------------------------------------------------------
Ran 14 tests in 0.004s

OK
```

重构前基线测试原始输出：

```
test_default_fixture_loads (test_baseline.BaselineSmokeTests) ... ok
test_default_summary_shape (test_baseline.BaselineSmokeTests) ... ok
test_list_command_runs (test_baseline.BaselineSmokeTests) ... ok
test_valid_money_inputs (test_baseline.BaselineSmokeTests) ... ok

----------------------------------------------------------------------
Ran 4 tests in 0.001s

OK
```

6. `git diff` / `git status --short` → 仅 `ledger/cli.py`、`ledger/query.py` 修改，`ledger/dates.py`、`tests/test_t07_dates.py` 新增；HEAD 未移动。

## 耗时

约 5 分钟（探查与基线记录约 2 分钟，重构与新增测试约 1 分钟，重构后验证与文档约 2 分钟）。测试套件本身运行 0.004s。

## 尚未完成的要求

无。题面全部要求已完成：共用实现抽取至 `ledger/dates.py`；`filter_by_date` 签名/返回类型/ValueError 行为与排他过滤语义保持；CLI 非法日期错误输出 `ledger: error: <field> must use YYYY-MM-DD` 与退出码 2 保持；未做无关改动；未删改既有测试；未增加运行时依赖；已增加兼容性测试；`python3 -m unittest discover -s tests -v` 全绿（14/14）。

## 会话隔离状态

- 仅读写本次运行目录 `<评测根目录>/zcode/输出/zcode/T07/R01/` 内文件（workspace 子目录及本结果文件），未访问其他运行目录或基准仓库。
- 题目源文件未被修改：workspace 为冻结提交 ed2390f2df8252f062abd9123e20f6fffca7e5ed 的独立副本，改动全部留在该副本的工作区（未提交、未推送），HEAD 未移动。
- 未联网，未安装任何包（仅标准库 python3 3.9.6）。
- 既有测试 `tests/test_baseline.py` 与 T08 复现目录 `tests_t08/` 均未改动。
