# 参考解法：用来比较，不覆盖挑战

先自己修改 `src/ticket_write/service.py` 并解释五条测试，再看 [closer.py](closer.py)。
参考函数先核验审批，查已有回执，验证 OPEN，再最多尝试两次写入。
捕获超时后按原号查询；第二次仍没有已知结果就抛出未知态异常，不冒称失败。

`lookup` 在本内存账本中是同步的；生产系统还需要持久化去重、处理在途请求及明确一致性契约。
OPEN 检查不是原子条件更新，因此参考代码也不解决并发修改。不要把它直接当生产实现。

## 到期时间为什么也要签

[expiry.py](expiry.py) 把 `operation_id + args_digest + expires_at` 一起签名。
验证时既核对签名，也要求可信时钟 `now < expires_at`。
如果到期时间不入签名，调用方可以自行把昨天改成明天。
如果只在第一次写之前检查，排队或重试可能发生在过期之后。
参考中时钟可注入，所以边界测试不靠 sleep，不受运行快慢影响。

扩展练习：先写三条测试——过期、恰好到期、修改 expires_at。
每条都要求写工具调用为 0。再做“第一次超时后到期”的测试：网络尝试共 1 次，不执行第二次写。
参考答案在 [test_reference.py](tests/test_reference.py)。原始挑战的审批类保持不动。

## Agent 示范读法

[agent_loop.py](agent_loop.py) 的 `example_chooser(observations)` 是离线决策替身。
执行器不假设它可信：检查工具白名单、参数与证据，审批只由测试 harness 签发，最多四轮。
这说明哪里将来可以接模型，不意味着这个固定选择器本身就是智能 Agent。
实际模型仍需结构化输出校验、真实权限、恢复状态和评测，本课不实现这些外围系统。

读每轮 observation → decision → result：为何先查状态，再查相似件？
为何审批有效也不能越过状态冲突？为何有了回执就不再问模型是否要重试？

```bash
python -m pytest -q reference/tests
```

独立参考测试应全部通过；`python -m pytest -q tests` 仍检验挑战里的 Closer。
不要把“运行过参考”写成“独立实现”，也不要把保存自评当成测试证据。
