# 04 — 套餐历史提供下架续费入口

**What to build:** 当前资产所有人查看套餐历史时，每条历史记录都能获得基于当前事实计算的购买资格。待生效、生效中、已用完和已过期套餐均可在符合条件时提供下架续费入口；同一套餐的多条历史记录展示一致决策。

**Blocked by:** 01 — 建立统一套餐可售决策与真实历史资格

**Status:** ready-for-agent

**架构通道:** Query。

**完整业务边界:** 本票只迁移和收口 `GET /api/c/v1/asset/package-history` 的权限、分页、批量可售投影与 DTO 契约。明确不修改套餐使用状态、不把历史行作为写授权、不实现前端页面或跨世代历史续费。

- [ ] 查询继续限定当前资产与当前 generation，并保持现有套餐类型、状态筛选、分页、排序和统一错误格式。
- [ ] 每条历史记录增加 `can_purchase`、`purchase_mode` 和 `disabled_reason`，现有 `package_id` 作为续费提交的稳定标识，`package_usage_id` 仅用于展示和追踪。
- [ ] 状态为待生效、生效中、已用完或已过期的真实购买记录均可形成下架续费资格；已过期记录具有可实际消费的 `renew_only` 契约。
- [ ] 同一套餐存在多条历史记录时，各条记录基于套餐级当前购买资格返回相同结果；即使某一行自身已失效，只要同套餐另有有效历史，仍按统一当前决策投影。
- [ ] 套餐当前正常在售时返回 `normal`；当前渠道下架且资格成立时返回 `renew_only`；禁用、无有效历史、未授权或价格异常时返回 `disabled` 和稳定原因。
- [ ] 套餐、渠道分配和历史资格按当前页套餐 ID 批量读取或使用等价集合查询，同套餐复用决策结果，不产生逐行或逐套餐 N+1。
- [ ] PostgreSQL 与 HTTP 集成测试覆盖四种有效历史状态、已失效、软删除、退款撤销、同套餐多记录、不同套餐、不同资产、不同世代、分页筛选及查询次数边界。
