# 会双写的关闭逻辑

Ledger（对面的账本）行为是对的。`Closer` 在超时后换号，也不校验审批摘要。测试是对的，刚拉下来是红的。

原版教师答案在 `ai-agent/labs/clean-room-ownership/`。先改这份。改绿了再去空目录写 FastAPI 那一份。

## 跑

```bash
cd empty-dir/lab
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -e '.[dev]'
pytest -q
```

## 改哪里

只需要动 `src/ticket_write/service.py`。签名已经是对的：

```python
Closer.close(ticket_id, intent, approval) -> Receipt
```

`intent.operation_id` 进门时就有。不要在重试里生成新号。

账本会按你注入的故障抛 `WriteTimeout(after_commit=...)`。它也提供 `lookup(operation_id)`。

审批用 `Authority.verify(...)`。摘要对不上就不要调用 `ledger.write`。

## 测试在锁什么

| 测试 | 要看到的 |
| --- | --- |
| 写上了才超时 | `committed_writes == 1`，而且调用过 `lookup` |
| 还没写上就超时 | 两次尝试的 `operation_id` 相同，最终写 1 次 |
| 审批后改 note | 写工具调用次数是 0 |
| 同一意图发两次 | 同一张回执，提交次数仍是 1 |

主路径能关工单，测试里已经有一条是绿的。其余三条指着超时和审批。

## 不要做的

- 不要先打开教师答案再抄
- 不要在测试里改断言来就绿
- 不要让 AI 一次性重写整个包
