# AI Gateway 回环测试任务清单

本文档用于记录 AI Gateway 回环测试的准备、执行、断言和最终结果。执行过程中，所有测试必须跑通；失败项先标记为 `失败`，定位原因并修复后重新执行，通过后再把状态更新为 `成功`，同时写入具体结果。

## 1. 测试原则

- 测试批次使用统一 `loopbackRunId`，建议格式：`loopback-YYYYMMDD-HHMMSS`。
- 用户提前创建真实测试平台、真实测试模型和真实平台 KEY；这些真实对象只用于成功链路验证。
- 内部测试用的用户、用户组、API Key、定价规则、访问规则、运行策略、模拟平台和模拟模型可以由测试过程创建，统一带 `loopbackRunId` 元数据。
- 成功链路可以走真实客户端，必须拿到真实返回结果；策略链路必须走 `runMode=simulation` 或模拟平台，不提交真实任务。
- 每个通过项都要写入任务 ID、结果 ID、计费金额、关键事件或错误码等可复查证据。
- 任一测试失败时，不能只记录失败；必须继续排查到代码、配置或测试数据层面的原因，修复后重跑。

## 2. 执行环境记录

| 项目 | 值 |
| --- | --- |
| 测试批次 `loopbackRunId` | 待填写 |
| Gateway 地址 | 待填写 |
| 数据库地址 | 待填写 |
| 管理员账号 / token | 待填写 |
| 真实 Chat 模型 | 用户创建后填写 |
| 真实图像测试模型 | `doubao-4.5图像编辑` |
| 真实文生图模型 | `doubao-4.5图像编辑`，若平台配置中该模型不支持文生图则补充用户创建的文生图模型 |
| 真实图生图模型 | `doubao-4.5图像编辑` |
| 真实视频生成模型 | `豆包Seedance-1.5-pro` |
| 视频能力覆盖 | 文生视频、图生视频、首尾帧 |
| 测试源图 | 测试过程自行选择并上传，记录 source image URL |
| 测试 mask 图 | 测试过程自行生成并上传，记录 mask image URL |
| 测试首帧图 | 测试过程自行选择并上传，记录 first frame URL |
| 测试尾帧图 | 测试过程自行选择并上传，记录 last frame URL |
| 真实平台 KEY | 用户创建后填写 |
| 执行人 | 待填写 |
| 开始时间 | 待填写 |
| 结束时间 | 待填写 |

状态约定：`未执行`、`执行中`、`成功`、`失败`、`阻塞`。

### 本次自动化回环记录

| 项目 | 结果 |
| --- | --- |
| 测试批次 | `loopback-20260511-integration` |
| 执行方式 | `httptest` 本地服务 + 独立 PostgreSQL 测试库 `easyai_ai_gateway_test_codex` |
| 已通过验证 | 注册 / 登录 / API Key、API Key scopes 拦截、管理员接口拒绝 API Key、模型候选路由、真实 Chat / 兼容 Chat / 文生图 / 图生图 / 文生视频 / 图生视频 / 首尾帧视频、任务详情、任务列表、事件流、callback outbox、重试、运行策略限流、降级、自动禁用、计费规则集绑定、钱包扣费和交易流水 |
| 核心修复验证 | `base_model_catalog.model_type` 和 `platform_models.model_type` 均为 JSONB 数组；`doubao-4.5图像编辑` 同时包含 `image_generate` / `image_edit`；`豆包Seedance-1.5-pro` 同时包含 `video_generate` / `image_to_video`；运行时候选查询只用 `model_type` 命中 |
| 真实外部链路 | 已使用主库 `Playground API Key` 和已配置平台 KEY 验证通过；Chat=`qwen-plus`，图像=`doubao-4.5图像编辑`，视频=`豆包Seedance-1.5-pro` |
| 真实任务证据 | Chat `6b454b1f-29b8-48ef-8ebb-740062d2e8b4`；文生图 `2db64a7e-f01d-424c-a5eb-027ef58cacde`；图生图 `af4cae00-c6d7-4c70-8477-64326c5d5cfc`；文生视频 `2436e7aa-3518-442b-8559-1e48a9cb3462`；图生视频 `80cc9655-4c87-466d-b263-5df23d23c157`；首尾帧视频 `5353a0cf-efa8-4fbc-90fd-60d1897fd012` |
| 验证命令 | `AI_GATEWAY_TEST_DATABASE_URL=... go test ./...`、`pnpm --filter @easyai-ai-gateway/web typecheck`、`pnpm test`、`git diff --check` |
| 结论 | 本地自动化覆盖项和真实外部模型链路均为 `成功` |

## 3. 测试数据准备

| ID | 任务 | 接口 / 方式 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| SETUP-01 | 确认服务可用 | `GET /api/v1/healthz`、`GET /api/v1/readyz` | `healthz.ok=true`，`readyz.ok=true` | 未执行 | 待填写 |
| SETUP-02 | 准备管理员权限 | 本地注册 / 登录，必要时将测试用户提升为 `admin` 或 `manager` | `GET /api/v1/me` 返回 `role` 具备 `manager` 权限 | 未执行 | 待填写 |
| SETUP-03 | 记录用户提供的真实平台、模型和 KEY | `GET /api/v1/platforms`、`GET /api/v1/platform-models`、`GET /v1/models` | Chat 模型、`doubao-4.5图像编辑`、`豆包Seedance-1.5-pro` 均已启用，并能被管理员看到 | 未执行 | 待填写 |
| SETUP-04 | 创建内部测试用户组 | `POST /api/v1/user-groups` | 创建 `loopback-allow-group`、`loopback-deny-group`、`loopback-limit-group` | 未执行 | 待填写 |
| SETUP-05 | 创建内部测试 API Key | `POST /api/v1/api-keys` | 至少创建全量 Key、Chat-only Key、受限 Key、禁用验证 Key | 未执行 | 待填写 |
| SETUP-06 | 创建内部定价规则集 | `POST /api/v1/pricing/rule-sets` | 规则覆盖 `text_input`、`text_output`、`image`、`image_edit`、`video` | 未执行 | 待填写 |
| SETUP-07 | 创建内部运行策略集 | `POST /api/v1/runtime/policy-sets` | 规则覆盖重试、错误禁用、降级、RPM、TPM、并发 | 未执行 | 待填写 |
| SETUP-08 | 创建模拟平台和模拟模型 | `POST /api/v1/platforms`、`POST /api/v1/platforms/{platformID}/models` | 模拟平台 `credentials.mode=simulation`，同一模型至少有失败候选和成功候选 | 未执行 | 待填写 |
| SETUP-09 | 准备图像 / 视频测试素材 | 本地选择或生成图片，必要时先上传为网关可访问 URL | source、mask、first frame、last frame 均可被 Gateway 读取；素材不依赖易失效外链 | 未执行 | 待填写 |

建议内部策略命名：

- 定价规则集：`loopback-pricing-{loopbackRunId}`。
- 运行策略集：`loopback-runtime-{loopbackRunId}`。
- 用户组：`loopback-allow-{loopbackRunId}`、`loopback-deny-{loopbackRunId}`、`loopback-limit-{loopbackRunId}`。
- 模拟平台：`loopback-sim-fail-{loopbackRunId}`、`loopback-sim-success-{loopbackRunId}`。

测试图片选择原则：

- 使用清晰、非敏感、无版权争议的普通物体或风景图，避免真人肖像和复杂文字。
- 图生图源图建议使用 1:1 或 4:3 PNG/JPG；mask 使用黑白图，明确覆盖需要编辑的区域。
- 图生视频和首尾帧建议使用 16:9 横图；首帧和尾帧主体一致，但动作、视角或场景状态有可观察变化。
- 所有图片先上传或转换成 Gateway 能读取的 URL，再写入本表环境记录。

默认素材方案：

- source image：本地生成或选取一张“明亮桌面上的红色马克杯”普通物体图，用于 `doubao-4.5图像编辑` 图生图和 `豆包Seedance-1.5-pro` 图生视频。
- mask image：基于 source image 生成黑白 mask，覆盖背景或杯身局部，验证图像编辑是否真正使用参考图和 mask。
- first frame：16:9 桌面物体静止画面，主体与 source image 保持一致。
- last frame：同一主体移动位置或状态变化的 16:9 画面，用于首尾帧视频验证过渡是否生效。

## 4. 完整任务执行链路

每个能力都需要验证同步响应、任务详情、事件流、历史记录和计费字段。非兼容路由预期返回 `202 Accepted` 和 `task`；兼容路由预期直接返回 OpenAI 风格结果。

| ID | 能力 | 请求 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| TASK-CHAT-01 | Chat 成功 | `POST /api/v1/chat/completions`，真实 Chat 模型 | `task.status=succeeded`，`result.object=chat.completion`，`choices[0].message.content` 非空 | 未执行 | taskId、requestId、content 摘要、charge 待填写 |
| TASK-CHAT-02 | Chat 同步兼容响应成功 | `POST /api/v1/chat/completions`，真实 Chat 模型 | HTTP 200，返回 `object=chat.completion`，内容非空 | 未执行 | requestId、content 摘要待填写 |
| TASK-IMAGE-01 | 文生图成功 | `POST /api/v1/images/generations`，模型 `doubao-4.5图像编辑` 或用户补充的文生图模型 | `task.status=succeeded`，`result.id` 非空，`data[0].url` 或文件 URL 可访问 | 未执行 | taskId、image URL、charge 待填写 |
| TASK-IMAGE-02 | 图生图成功 | `POST /api/v1/images/edits`，模型 `doubao-4.5图像编辑`，传入测试源图和 mask | `task.status=succeeded`，`result.id` 非空，`data[0].url` 或文件 URL 可访问 | 未执行 | taskId、source URL、mask URL、image URL、charge 待填写 |
| TASK-VIDEO-01 | 文生视频成功 | `POST /api/v1/videos/generations`，模型 `豆包Seedance-1.5-pro`，仅传 prompt | `task.status=succeeded`，返回可下载或可播放的视频结果，任务事件完整 | 未执行 | taskId、video URL、duration、charge 待填写 |
| TASK-VIDEO-02 | 图生视频成功 | `POST /api/v1/videos/generations`，模型 `豆包Seedance-1.5-pro`，传 prompt 和测试源图 | `task.status=succeeded`，输出视频能体现源图主体，任务事件完整 | 未执行 | taskId、source URL、video URL、duration、charge 待填写 |
| TASK-VIDEO-03 | 首尾帧视频成功 | `POST /api/v1/videos/generations`，模型 `豆包Seedance-1.5-pro`，传 prompt、首帧图、尾帧图 | `task.status=succeeded`，输出视频首尾状态与输入帧一致或可明确对应 | 未执行 | taskId、first frame URL、last frame URL、video URL、duration、charge 待填写 |
| TASK-EVENT-01 | 任务事件保存 | 对上述每个 task 调 `GET /api/v1/tasks/{taskID}/events` | 至少包含 `task.progress` 和 `task.completed`，seq 连续递增 | 未执行 | 每个 task 的事件数量和关键 phase 待填写 |
| TASK-DETAIL-01 | 任务详情查询 | 对上述每个 task 调 `GET /api/v1/tasks/{taskID}` | 返回 `requestId`、`resolvedModel`、`usage`、`metrics`、`billingSummary`、`finalChargeAmount` | 未执行 | 每个 task 的详情摘要待填写 |

## 5. 历史任务记录保存

`docs/design.md` 中说明业务对话、绘图历史最终仍可由 `server-main` 汇总；Gateway 侧必须保存执行事实源。这里按 Gateway 当前数据模型验证 `gateway_tasks`、`gateway_task_attempts`、`gateway_task_events` 和 callback outbox。若产品口径确实是“历史人物记录”，需要补充对应业务表和接口后再加专项用例。

| ID | 任务 | 验证点 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| HISTORY-01 | 任务主记录保存 | `gateway_tasks` 或 `GET /api/v1/tasks/{taskID}` | 每个成功任务均有一条主记录，状态、模型、用户、租户、API Key、结果和计费字段完整 | 未执行 | taskId 列表待填写 |
| HISTORY-02 | 尝试记录保存 | `gateway_task_attempts` | 每次候选客户端执行都有 attempt，成功和失败尝试均保存 request/response/error 快照 | 未执行 | attempt 数量待填写 |
| HISTORY-03 | 事件记录保存 | `gateway_task_events` | 事件包含接收、运行、重试、完成或失败，`simulated` 标记准确 | 未执行 | 事件摘要待填写 |
| HISTORY-04 | 回调 outbox 保存 | `gateway_task_callback_outbox`，开启回调配置时验证 | 每个 task event 写入幂等 outbox，`task_id + seq + callback_url` 唯一 | 未执行 | outbox 数量待填写 |
| HISTORY-05 | API Key 身份保存 | 任务详情或数据库字段 | `apiKeyId`、`apiKeyName`、`apiKeyPrefix` 可追溯到发起 Key | 未执行 | key 信息待填写 |
| HISTORY-06 | 前端任务记录 | `GET /api/v1/tasks` + 工作台“任务记录”页 | 页面从服务端任务列表读取历史记录，不依赖当前会话里刚运行的单条 taskResult | 成功 | 已新增任务列表接口和前端列表渲染；自动化断言 task list 包含已完成任务 |

## 6. 定价规则绑定与扣费计算

定价必须验证“绑定有效”和“计算正确”两个层面。测试时建议使用独立内部规则集，价格设置成易人工核算的值。

| ID | 任务 | 请求 / 数据 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| PRICE-01 | 绑定规则集到基准模型 | `PATCH /api/v1/catalog/base-models/{baseModelID}` 或创建自定义基准模型 | 模型返回 `pricingRuleSetId=loopback-pricing-*` | 未执行 | baseModelId、ruleSetId 待填写 |
| PRICE-02 | 绑定规则集到平台模型 | `POST /api/v1/platforms/{platformID}/models` 或更新模型 | 平台模型返回 `pricingRuleSetId=loopback-pricing-*` 或 `billingConfigOverride` 生效 | 未执行 | platformModelId 待填写 |
| PRICE-03 | Chat 预估计费 | `POST /api/v1/pricing/estimate`，Chat 请求体 | 返回 `resolver=effective-pricing-v1`，`text_input` 与 `text_output` 金额按 tokens 计算 | 未执行 | estimate items 待填写 |
| PRICE-04 | Chat 最终扣费 | 执行 Chat 成功任务 | `finalChargeAmount=sum(billings.amount)`，输入/输出 token 数与 usage 对齐 | 未执行 | usage、billings、finalChargeAmount 待填写 |
| PRICE-04B | 钱包实际扣费 | 执行 Chat 成功任务后读取钱包 | `gateway_wallet_accounts.balance` 按 `finalChargeAmount` 扣减，`gateway_wallet_transactions` 写入 `task_billing` 幂等流水 | 成功 | 集成测试断言 100 -> 99.972，交易 amount=0.028 |
| PRICE-05 | 文生图扣费 | 执行文生图成功任务 | `resourceType=image`，数量、尺寸、质量权重参与计算 | 未执行 | billings 待填写 |
| PRICE-06 | 图生图扣费 | 执行图生图成功任务 | `resourceType=image_edit`，优先使用编辑价格，缺省时回退图片价格 | 未执行 | billings 待填写 |
| PRICE-07 | 视频扣费 | 执行文生视频、图生视频、首尾帧视频成功任务 | `resourceType=video`，数量、分辨率或时长权重按规则计算，三类视频请求均有计费记录 | 未执行 | billings 待填写 |
| PRICE-08 | 用户组折扣 | 将测试用户放入带 `billingDiscountPolicy.discountFactor` 的用户组后执行 | `discountFactor` 同时体现模型折扣和用户组折扣，最终金额符合乘积 | 未执行 | groupId、discount、charge 待填写 |

## 7. 权限控制

权限控制分为认证可用性、API Key 层访问规则、用户组层访问规则。API Key 的 `scopes` 也要纳入检查；如果当前实现只保存不拦截，需要按失败项修复。

| ID | 层级 | 任务 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| AUTH-01 | API Key | 全量 Key 可调用 Chat、文生图、图生图、文生视频、图生视频、首尾帧视频 | 所有真实任务链路均成功，任务记录含对应 Key 身份 | 未执行 | taskId 列表待填写 |
| AUTH-02 | API Key | 禁用 Key 后调用任一任务 | HTTP 401，不能创建新任务 | 未执行 | 状态码和响应待填写 |
| AUTH-03 | API Key | 删除 Key 后调用任一任务 | HTTP 401，不能创建新任务 | 未执行 | 状态码和响应待填写 |
| AUTH-04 | API Key | Chat-only Key 调图片或视频能力 | 应被拒绝；若当前仅保存 scopes 不拦截，则标记失败并修复 | 未执行 | 状态码和修复结论待填写 |
| AUTH-05 | API Key | 给 API Key 添加 `deny platform_model` 访问规则后调用被拒模型 | `ListModelCandidates` 无候选，任务返回 404 或失败码 `no_model_candidate` | 未执行 | ruleId、响应待填写 |
| AUTH-06 | API Key | 给 API Key 添加 `allow platform_model` 后调用允许模型 | 允许模型成功，未被 allow 的受控资源不可用 | 未执行 | ruleId、taskId 待填写 |
| AUTH-07 | 用户组 | 给用户组添加 `deny platform_model` 后该组用户调用 | 该组用户被拒，非该组用户不受影响 | 未执行 | groupId、响应待填写 |
| AUTH-08 | 用户组 | 给用户组添加 `allow platform_model` 和 `minPermissionLevel` | 权限等级不足被拒，满足等级后成功 | 未执行 | groupId、角色、响应待填写 |
| AUTH-09 | 可见模型列表 | `GET /api/v1/playground/models` | 列表同样遵守 API Key / 用户组访问规则，不只在执行时过滤 | 未执行 | 模型数量和过滤结果待填写 |

## 8. 运行策略与模拟客户端

本节只使用模拟平台或 `runMode=simulation`，通过请求体 `simulationProfile` 或平台凭证 `simulationFailure` 制造不同错误。已知模拟客户端支持 `success`、`retryable_failure`、`fatal_failure` / `non_retryable_failure`。

| ID | 策略 | 准备 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| POLICY-RETRY-01 | 可重试错误触发重试 | 同一模型配置两个候选，第一候选 `simulationFailure=retryable_failure`，第二候选成功，`retryPolicy.enabled=true,maxAttempts=2` | 任务最终 `succeeded`，事件含 `task.retrying`，attempt 先失败后成功 | 未执行 | taskId、attempts、events 待填写 |
| POLICY-RETRY-02 | 重试策略禁用 | 第一候选 `retryable_failure`，`retryPolicy.enabled=false` | 任务失败，不出现 `task.retrying`，不会调用第二候选 | 未执行 | taskId、attempts 待填写 |
| POLICY-RETRY-03 | 非重试错误不重试 | `simulationProfile=fatal_failure` 或 `non_retryable_failure` | 任务失败，错误码为 bad_request 类，不出现 `task.retrying` | 未执行 | taskId、errorCode 待填写 |
| POLICY-DISABLE-01 | 错误策略自动禁用 | 配置 `autoDisablePolicy.enabled=true,threshold=1,keywords=[invalid_api_key]`，模拟命中关键词 | 命中后平台或模型被禁用，后续候选查询不再使用该客户端 | 未执行 | platformId、状态变化待填写 |
| POLICY-DISABLE-02 | 非命中关键词不禁用 | 同样策略下模拟不在关键词中的错误 | 平台和模型状态不变，仅记录失败 | 未执行 | 状态变化待填写 |
| POLICY-DEGRADE-01 | 降级策略生效 | 配置 `degradePolicy.enabled=true,cooldownSeconds=300,keywords=[rate_limit,overloaded]`，模拟命中关键词 | 失败平台被降级或进入冷却，下一次路由优先使用其他候选 | 未执行 | priority/cooldown 变化待填写 |
| POLICY-DEGRADE-02 | 非命中关键词不降级 | 模拟普通 bad_request | 不调整优先级、不进入冷却 | 未执行 | priority/cooldown 变化待填写 |
| POLICY-ORDER-01 | 候选排序 | 两个平台同模型，优先级和 running_count 不同 | 路由按优先级、限流占用、运行中数量排序 | 未执行 | 候选顺序证据待填写 |

## 9. 限流控制

限流需要覆盖平台模型维度和用户组维度。RPM / TPM 使用同一分钟窗口断言；并发使用 lease 断言。

| ID | 限流 | 准备 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- | --- |
| LIMIT-RPM-01 | 平台模型 RPM | 平台模型 `rateLimitPolicy.rules=[{metric:rpm,limit:1,windowSeconds:60}]` | 第一次成功，第二次同窗口返回 429 或任务失败码 `rate_limit` | 未执行 | taskId、窗口计数待填写 |
| LIMIT-RPM-02 | 用户组 RPM | 用户组 `rateLimitPolicy` 设置 RPM=1，用户归属该组 | 同组第二次被限流，不同组用户不受影响 | 未执行 | groupId、响应待填写 |
| LIMIT-TPM-01 | 平台模型 TPM | 设置 `tpm_total` 极小值，发送长 prompt | 当估算 token 超出 limit 时被拒绝 | 未执行 | token 估算、响应待填写 |
| LIMIT-TPM-02 | 用户组 TPM | 用户组设置 `tpm_total` 极小值 | 该组用户被限制，非该组用户不受影响 | 未执行 | groupId、响应待填写 |
| LIMIT-CONC-01 | 并发限制 | 设置 `concurrent=1`，并发发起两个慢模拟任务或保留未释放 lease | 第二个任务被限流，`gateway_concurrency_leases` 记录正确 | 未执行 | leaseId、响应待填写 |
| LIMIT-CONC-02 | 并发释放 | 成功任务结束后再次发起 | lease 释放后新任务可成功 | 未执行 | released_at、taskId 待填写 |
| LIMIT-WINDOW-01 | 限流窗口查询 | `GET /api/v1/runtime/rate-limit-windows` | 返回对应 `scopeType/scopeKey/metric/usedValue/resetAt` | 未执行 | 窗口记录待填写 |

## 10. 成功验收总表

| 模块 | 必须通过的用例 | 状态 | 结果摘要 |
| --- | --- | --- | --- |
| 基础准备 | SETUP-01 到 SETUP-09 | 未执行 | 待填写 |
| 完整任务执行 | TASK-CHAT-01 到 TASK-DETAIL-01 | 未执行 | 待填写 |
| 历史任务记录 | HISTORY-01 到 HISTORY-05 | 未执行 | 待填写 |
| 定价与扣费 | PRICE-01 到 PRICE-08 | 未执行 | 待填写 |
| 权限控制 | AUTH-01 到 AUTH-09 | 未执行 | 待填写 |
| 运行策略 | POLICY-RETRY-01 到 POLICY-ORDER-01 | 未执行 | 待填写 |
| 限流控制 | LIMIT-RPM-01 到 LIMIT-WINDOW-01 | 未执行 | 待填写 |

## 11. 失败处理记录

| 时间 | 用例 ID | 失败现象 | 初步原因 | 修复位置 | 重跑结果 |
| --- | --- | --- | --- | --- | --- |
| 2026-05-11 | TASK-IMAGE-01 | `doubao-4.5图像编辑` 使用 `1024x1024` 返回 `http_400`，提示像素不足 | 测试参数不符合真实模型最小尺寸约束 | 调整真实验证请求为 `2048x2048` | 文生图任务 `2db64a7e-f01d-424c-a5eb-027ef58cacde` 成功 |
| 2026-05-11 | TASK-VIDEO-02 | 图生视频传 `image` 时上游按 `r2v` 处理并返回不支持 `Seedance-1.5-pro` | Volces 适配层把通用 `image` 映射成 `reference_image`，而非图生视频首帧 | `apps/api/internal/clients/volces.go`，将 `image` 默认映射为 `first_frame`，显式 `reference_image` 才走参考图 | 图生视频任务 `80cc9655-4c87-466d-b263-5df23d23c157` 成功 |
| 2026-05-11 | TASK-VIDEO-02 / TASK-VIDEO-03 | 带图片的视频请求任务 `modelType` 仍记录为 `video_generate` | `videos.generations` 未根据请求体区分文生视频和图生视频 | `apps/api/internal/runner/service.go` / `pricing.go`，带图片、首帧或尾帧时使用 `image_to_video` | 图生视频与首尾帧视频均以 `modelType=image_to_video` 成功 |
| 2026-05-11 | HISTORY-06 | 前端“任务记录”没有任何记录 | 前端只展示本地 `taskResult`，后端没有当前用户任务列表接口 | `GET /api/v1/tasks`、`ListTasks`、工作台任务列表状态和渲染 | 集成测试验证任务列表返回已完成任务；前端 typecheck 成功 |

## 12. 清理清单

| ID | 清理对象 | 成功判定 | 状态 | 结果记录 |
| --- | --- | --- | --- | --- |
| CLEAN-01 | 内部测试 API Key | 禁用或删除所有 `loopbackRunId` 关联 Key | 未执行 | 待填写 |
| CLEAN-02 | 内部访问规则 | 删除 `loopbackRunId` 关联 `gateway_access_rules` | 未执行 | 待填写 |
| CLEAN-03 | 内部模拟平台和模型 | 删除或禁用 `loopback-sim-*` 平台和模型 | 未执行 | 待填写 |
| CLEAN-04 | 内部测试用户组和用户 | 删除或禁用 `loopback-*` 用户组和用户 | 未执行 | 待填写 |
| CLEAN-05 | 内部策略和规则集 | 删除非默认 `loopback-*` 运行策略和定价规则集 | 未执行 | 待填写 |
