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

---

# BENCH-RUN T05 R01

# T05：增加 JSON 输出 — 结果：PASS

## 题面（逐字）

> # T05：增加 JSON 输出
>
> 为 `python3 -m ledger summary` 增加精确选项 `--format json`。不带该选项的默认输出必须保持基准行为。JSON 必须可由标准 JSON 解析器读取，并包含 `count`、`total_cents`、`by_category` 三个字段；金额为整数分，`by_category` 的键是原始类别文本、值为该类别整数分总和，键按 Unicode 码点升序输出。相同输入必须产生稳定结果；stdout 只能有 JSON，不得混入日志或说明文字。
>
> 为新选项新增测试和简短用法说明；不得删改已有测试或增加运行时依赖。运行 `python3 -m unittest discover -s tests -v`，并报告实际结果。

## 实际改动

1. **`ledger/summary.py`**：
   - 新增 `summarize_by_category(transactions)`：按原始类别文本精确累加，返回 `{类别: 整数分}`。
   - 新增 `format_summary_json(summary)`：`json.dumps(..., ensure_ascii=False, sort_keys=True)` —— `sort_keys=True` 使嵌套 `by_category` 的键按 Unicode 码点升序（Python 字符串排序即码点序），且保证相同输入输出逐字节稳定。
   - `summarize()` 与 `format_summary()` 原样未动，默认输出保持基准行为。
2. **`ledger/cli.py`**：`summary` 子命令新增 `--format`，`choices=["json"]`（非法值由 argparse 以标准参数错误拒绝，退出码 2）；`main` 的 summary 分支在 `--format json` 时把 `by_category` 并入 `summarize()` 结果并经 `format_summary_json` 输出，否则走原有 `format_summary`。stdout 仅有 `print(output)` 一处，JSON 输出时不混入任何其他文字。
3. **`tests/test_summary_json.py`（新增）**：6 项测试 —— 字段与数值（`count=6`、`total_cents=11756`、`by_category` 五类精确值）、键码点序（`["Food","Transit","Travel","food","家庭"]`）、stdout 纯 JSON、两次运行输出一致、默认输出不含 JSON、非法 `--format xml` 非零退出。
4. **`docs/usage.md`**：在"汇总"一节补充一行 `--format json` 用法说明。
5. 未删改已有测试，未增加运行时依赖（`json` 为标准库）。

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

```text
$ 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_by_category_keys_sorted_by_codepoint (test_summary_json.SummaryJsonTests) ... ok
test_default_output_unchanged (test_summary_json.SummaryJsonTests) ... ok
test_invalid_format_rejected (test_summary_json.SummaryJsonTests) ... ok
test_json_shape_and_values (test_summary_json.SummaryJsonTests) ... ok
test_stable_output (test_summary_json.SummaryJsonTests) ... ok
test_stdout_is_json_only (test_summary_json.SummaryJsonTests) ... ok
----------------------------------------------------------------------
Ran 10 tests in 0.003s
OK

$ python3 -m ledger summary --format json
{"by_category": {"Food": 1195, "Transit": 200, "Travel": 10010, "food": 1, "家庭": 350}, "count": 6, "total_cents": 11756}

$ python3 -m ledger summary
Transactions: 6
Total: $117.56        ← 默认输出与基准一致

$ python3 -m ledger summary --format xml
usage: ledger summary [-h] [--format {json}]
ledger summary: error: argument --format: invalid choice: 'xml' (choose from 'json')
exit=2
```

`git status --porcelain`：`M docs/usage.md`、`M ledger/cli.py`、`M ledger/summary.py`、`?? tests/test_summary_json.py`。

## 耗时

UNKNOWN（未使用计时工具精确测量；本题在数分钟内完成）。

## 未完成项

无。

## 会话隔离状态

本题使用独立 workspace（`输出/qoder/T05/R01/workspace/`），改动仅限该目录；未触碰基准仓库、题面或其他题目目录。
