---
name: api2business
description: >-
  Api2Business 开发、配置、部署和运行维护技能。用户要求安装、部署、升级、验证、
  排查 Api2Business，或操作账号、评分、上游、成本和经营核算时使用。
---

# Api2Business

- 本技能遵循 Skill(cli-spec)。

## 当前 Sub2API 架构

- 唯一 Sub2API 运行面是 NC01 的 `sub2api-nc01-native`。
- 唯一 Sub2API 业务数据库是 NC01 本地专用 PostgreSQL
  `127.0.0.1:55432/sub2api`。
- `api.pikapython.com`、`api.hwpod.com` 和 `sub.api2business.com` 只是入口或代理，
  不代表数据库 authority。
- 禁止将旧 PK01 或 `NC01-DOCKER` 的数据库地址写入配置、Secret、CLI 参数或示例。

## Api2Business L1 唯一运行面

- `https://api2business.hwpod.com` 是 Api2Business 唯一 L1 实例、唯一业务入口和唯一验收入口。
- CLI 的唯一 HTTP target 使用该公网地址；不得再配置或交付 `native-api`、`production`、`local` 等并列业务 target。
- 本机监听地址、Docker Compose/native profile 和 worker 内部回环地址只是唯一 L1 实例的实现细节，不构成第二个实例。
- `localhost`、`127.0.0.1` 和嵌入式 CLI 只能用于受控故障诊断或构建检查，不得用于业务结果、截图验收或邮件交付。
- L1 的 API、Web、worker、Temporal、数据库和账本必须由同一 owning 配置和同一公网入口关联；发现数据不一致时先修复入口映射，禁止创建并列实例。

## 工作区

- 新部署先克隆 `https://github.com/api2business/api2business.git`，再从克隆后的仓库加载本 skill。
- 从当前 Api2Business 仓库根目录执行命令。
- 使用 `config/api2business.yaml` 保存唯一 L1 的运行配置；该文件不得提交。
- 使用 `skills/api2business/scripts/api2business-cli.ts` 执行业务和生命周期操作。

## 从零部署（Bootstrap）

1. 准备 Git、Bun、PostgreSQL、Temporal 和可访问的 Sub2API 管理面。
2. 克隆仓库并进入工作区：

   ```bash
   git clone https://github.com/api2business/api2business.git
   cd api2business
   ```

3. 从克隆后的仓库加载 `skills/api2business/SKILL.md`，再读取
   `docs/reference/deployment.md`；不得从其他仓库或运行容器复制部署逻辑。
4. 安装依赖并创建不提交的本机配置：

   ```bash
   bun install --frozen-lockfile
   cp config/api2business.example.yaml config/api2business.yaml
   ```

5. 在仓库外准备 Secret 和持久化状态目录：
   - Secret 文件仅允许 owner 读取；
   - 配置只保存 `sourceRef`、环境变量名或挂载路径；
   - PostgreSQL 经营数据、账本、缓存和采样不得写入 Git 工作区。
6. 根据目标环境填写 `config/api2business.yaml`，再执行：

   ```bash
   bun skills/api2business/scripts/api2business-cli.ts \
     --config config/api2business.yaml \
     config validate
   bun run deploy:validate
   bun skills/api2business/scripts/api2business-cli.ts \
     --config config/api2business.yaml \
     native start --component all
   bun skills/api2business/scripts/api2business-cli.ts \
     --config config/api2business.yaml \
     native status --component all --json
   ```

7. 按“验收”章节完成检查：
   - 检查登录、主要数据页和至少一个异步作业；
   - 检查重启后的账本、缓存、采样和作业状态；
   - 任一步失败时保留首个断点，修复后从原入口复验。
   - 不跳过配置或 Secret 校验，也不把可修复的实现或取证缺口当作任务阻塞。

## 部署

- 先读取 `docs/reference/deployment.md`。
- 确认当前目录是已克隆的 Api2Business Git 工作区，不从运行容器或其他仓库拼装部署资产。
- 根据目标环境选择 Compose、Kubernetes、systemd、托管容器或其他部署方式。
- 不假定特定 CI/CD、代码托管、集群、主机名或网络入口。
- 发布前执行 `bun run deploy:validate`。
- 使用镜像摘要和配置摘要确认运行版本，禁止使用运行容器作为配置真相。

## 服务能力配置

- `gateway service-policy [--confirm] --over-api <absolute-http(s)-URL>` 预览或异步收敛
  Sub2API 原生模型准入；状态使用 `workflow status --id <workflow-id>`。
- 配置、自动收敛、语音拒绝与评分排除的唯一规则见
  [不提供语音服务](references/upstream-scheduling.md#不提供语音服务)。

## Secret

- Secret 只保存在仓库外。
- 通过配置中的 `sourceRef`、环境变量、只读文件或外部 Secret 管理器注入。
- 只输出 presence、fingerprint 和有界摘要，不输出值。

## 生命周期

- `native start|stop|status|logs --help` 直接显示对应操作帮助。
  - 查看帮助不要求配置存在，不启动服务，也不重印整个业务目录。

```bash
bun skills/api2business/scripts/api2business-cli.ts --config config/api2business.yaml native start --component all
bun skills/api2business/scripts/api2business-cli.ts --config config/api2business.yaml native status --component all
bun skills/api2business/scripts/api2business-cli.ts --config config/api2business.yaml native logs --component all --tail 100
bun skills/api2business/scripts/api2business-cli.ts --config config/api2business.yaml native stop --component all
```

- `native` 是唯一 L1 实例的生命周期入口，实际运行方式由配置选择；生命周期操作不得创建第二个业务实例。
- API 应快速返回作业 ID，长流程由 worker 执行。
- 数据库读取使用应用内排队读取通道，不从外部脚本直接连接业务数据库。

## 运行面与排队诊断

- HTTP 业务命令必须显式使用 `--over-api <绝对 http(s) URL>`。
  - URL 只匹配 owning YAML 中的唯一 HTTP target。
  - 不接受无值、布尔值、别名或隐式默认运行面。
  - 回执显示 `canonicalUrl`；续查命令保留该 URL。
- `reads query --file <broker-read-request.json> --over-api <绝对 http(s) URL>`：
  - 复用 `/api/internal/sub2api-read` 的排队只读通道。
  - 文件使用既有请求字段 `key`、`kind`、`sql` 和 `parameters`。
  - 按需声明 `priority`、`cacheMode` 和 `setupStatements`。
  - 查询只投影必要字段，不查询或输出 Secret、凭据和请求正文。
  - 不从人工脚本建立数据库连接。
  - 默认人类输出直接打印投影行，最多 50 行、12 列。
  - 零行时输出“无投影行”，不能把行数摘要当成没有查到正文。
  - 超出上限时给出 omitted，并用 `--json` 读取全部投影行。

## 领域操作

- 账号导入、生命周期和空闲探活读取 `references/account-operations.md`。
- 账号导入可用历史参数名 `--rate-multiplier <正整数>` 调整负载因子；该参数在导入
  payload 中必须写入 Sub2API 原生 `load_factor`，不得写入计费倍率
  `rate_multiplier`。省略时读取 `operations.accountImportDefaults.rateMultiplier`，普通导入与
  BugTeam 购买导入共用该字段。
- 普通 OpenAI OAuth 导入若未提供有效的 `credentials.model_mapping`，自动写入当前 OpenAI
  模型白名单并排除 `gpt-5.6-luna`；已有显式映射保持不变。
- 已有 OpenAI OAuth 账号可用 `accounts models disable-luna --accounts <id-or-range,...>
  --confirm --over-api <absolute-http(s)-URL>` 通过 Sub2API runtime 批量写入不含 Luna 的模型白名单；命令先校验
  全部目标均为 OpenAI OAuth，校验失败时不写入任何账号。
- 该默认限制只作用于普通 OAuth 导入；API-key、Grok OAuth 和
  `cutoffTrigger=public-recovery` 的复活导入不套用该策略。
- OAuth 退役计划可用 `--plan-type` 限定账号类型：
  - 默认 `--selection dead` 选择错误账号；`free`、`plus` 和 `team` 的限流账号也按死亡处理，`k12` 限流账号保留；
  - 显式 `--selection all` 选择指定单一类型的全部当前账号，且只允许用于整池范围。
- 退役清理边界：
  - 用户说“清理账号”或“退役账号”时，只允许处理 `platform=openai` 且 `type=oauth` 的账号。
  - API-key 账号禁止进入退役结算、删除或清理流程，即使它们属于同一业务池。
  - API-key 账号只能通过独立的上游管理流程处理，不得使用 OAuth 生命周期入口替代。
- 对缺少采购成本记录的整池账号，先用 `--scope pool --plan-type <type> --unit-cost-cny <CNY>`
  显式声明本批结算单价；该模式只支持单一账号类型，并在计划与确认回读中固定成本。
- 退役删除按 `operations.accountLifecycle.deleteBatchSize` 分批调用原生批量接口；单批失败会跳过并继续，终态只以排队回读为准，失败且有剩余账号时复用原计划恢复。
- 上游、评分、优先级、探活、定时稳定性观察和截图报错归因的唯一业务权威是
  [上游与调度](references/upstream-scheduling.md)。
- 该参考同时定义 API-key 切号模板的平台边界、成本补齐、评分分层和 V2 迁移；本技能只
  保留入口和命令，不复制第二套算法或状态机。
- TTFT、流式探活、缺失样本和评分参与边界只见上述参考，本技能不复制评分算法。
- 池级质量调查使用 `scores pool-quality --over-api <absolute-http(s)-URL>`，账号评分快照使用 `scores get`，
  需要刷新时使用 `scores rank --calls <N> --over-api <absolute-http(s)-URL>`。
- 池级刷新使用 `scores pool-quality-refresh --over-api <absolute-http(s)-URL>`，
  跟踪原 workflow 终态与各作用域采样时间；判定只见上述调度参考。
- 自动调度查询预算、索引优化和发布后写入核验见
  [评分查询性能与自动调度](references/upstream-scheduling.md#评分查询性能与自动调度)。
- 自动巡检须主动分析低分，修复已确认的调度问题，并邮件说明整体供给质量不足；
  唯一判定与处置规则见
  [自动巡检低分归因与处置](references/upstream-scheduling.md#自动巡检低分归因与处置)。
- V2 使用 `upstream-scheduling-v2 scopes|plan --over-api <absolute-http(s)-URL>` 或
  `upstream-scheduling-v2 snapshot --scope <scope> --over-api <absolute-http(s)-URL>` 只读查看；新鲜度告警或刷新失败
  排查默认读取缓存并由服务后台刷新；需要同步刷新时追加 `--refresh`，只读取最近成功的读模型缓存时追加 `--cache-only`，两者不可同时使用。使用
  `upstream-scheduling-v2 priority-run --scope <codex|claude|grok> --confirm --over-api <absolute-http(s)-URL>`
  通过原生 worker 执行一次指定作用域的手动优先级调整；作用域的
  `scoreRead`、`planRead`、`planWrite`、`priorityAutomation`、`idleProbe` 和
  `upstreamWrite` 只认 owning YAML；Codex、Claude、Grok 使用同一套平等作用域接口。
  自动探活必须先完成同作用域的手动探活核验，再打开
  `features.idleProbe`。V2 是唯一调度运行面；旧全局页面、工作流、写入 API、CLI 命令和
  配置字段已经删除，配置加载会拒绝这些退役字段，禁止兼容复活。
- 作用域自动探活周期配置在
  `operations.upstreamSchedulingV2.scopes.<scope>.idleProbeIntervalSeconds`；未声明时才
  回退到 `sub2api.idleProbe.intervalSeconds`，具体生效与工作流替换规则见
  `references/upstream-scheduling.md`。
- 充值候选使用 `upstreams recharge-candidates --over-api <absolute-http(s)-URL>`。
- 历史钱包回填使用 `upstreams usage-cache restore`，必须以 `--since <ISO时间>` 提供原观测时刻。
  - `upstreams usage-cache restore --help` 提供独立参数帮助，无需读取配置或连接运行面。
  - 只恢复已核实的旧值，不把回填时间作为余额新鲜度。
- 欠费、低余额和查询超时的判定见 `references/upstream-scheduling.md`。
- 充值使用 `upstreams recharge --base-url <https-url> --recharge-cny <CNY> --confirm --over-api <absolute-http(s)-URL>`；
  同一充值地址只记账一次并恢复该地址账号。余额读取的跨 host `walletKey`、缓存和失败
  保留见 [额度监控](references/quota-monitoring.md)。
- 充值确认后 CLI 立即返回异步 workflow ID，并做一次非阻塞只读状态与账号快照核验；最终一致性使用 `upstreams recharge-status --id <workflow-id> --over-api <absolute-http(s)-URL>`。
- 核验状态为 `pending`、`snapshot_mismatch` 或 `unavailable` 时，只表示作业未完成或读模型暂未追上，不代表充值失败；必须继续查询原 workflow。
- 充值请求超时重试时必须复用相同的 `--idempotency-key`，禁止生成新 key 重复提交同一笔充值。
- CLI 在提交传输异常时会回显本次幂等键和“结果未知”提示；只有复用该键重试，不能把传输异常当成未提交而生成新键。
- 精确错误链使用 `errors diagnose --request-id <request-id> --over-api <absolute-http(s)-URL>`。
- 按模型定位使用 `errors diagnose --model <exact-model-id> --limit <N> --top <N> --over-api <absolute-http(s)-URL>`。
- 单请求排障使用 `errors inspect --request-id <request-id> --over-api <absolute-http(s)-URL>`。
- 切号是否命中、候选是否耗尽、正文是否缺失，只以 `references/upstream-scheduling.md` 为准。
- 切号模板规则更新后必须覆盖同平台全部 API-key 上游，不得仅修报错账号或跨平台套用。
  - 全量选择、分平台执行和覆盖验收只见
    [切号模板同平台全量同步](references/upstream-scheduling.md#切号模板同平台全量同步)。
  - 使用 `reads query --file <查询文件> --over-api <绝对 URL>` 取得同平台完整 ID 集合。
  - 使用 `upstreams template --accounts <完整ID集合> --over-api <绝对 URL>` 查看计划。
  - 追加 `--confirm` 提交，再用 `upstreams status --id <workflow-id>` 和相同 URL 查询终态。
  - 人类终态直接给出 `targetCount`、`appliedCount`、`verifiedCount`、`failedCount`、`misalignedCount` 和 `skippedCount`。
  - 这些计数只证明作业终态；完整对象用 `--json`，账号规则仍要无缓存回读。
- 切号模板的匹配、近义短语、热加载、分组口语和新增上游收口，只以该参考为准。
- `upstreams template --confirm --over-api <absolute-http(s)-URL>` 按账号平台写入各自模板。
  - 未传 `--accounts` 时会处理 OpenAI、Anthropic 和 Grok，不能用来更新单一平台。
  - 单平台更新必须传入该平台全部未删除 API-key 账号 ID。
  - Grok 只读取 `config/failover-templates/grok.yaml`。
  - 套用 Grok 时不写 `pool_mode`，也不改写 Codex 或 Claude 规则。
  - 没有对应模板的平台仍进入 `skipped[]`，原因是 `platform-has-no-failover-template`。
- 新增上游、探活、切号和 Codex 强制 Responses 使用
  [新上游初始化](references/upstream-scheduling.md#新上游初始化)。
  - 创建自动执行；补齐使用 `upstreams initialize --accounts <id,id,...> [--confirm]`。
  - 两者都显式携带 `--over-api <绝对 http(s) URL>`；终态使用 `upstreams status`。
- 新增上游省略 `--rate`；占位费率与最终费率回读也只以该参考为准。
- 已有上游改配置使用 `upstreams update --id <account-id> [--base-url <https-url>] [--groups <id,id,...>] [--suffix <name>] [--rate <CNY/API_USD>] --confirm --over-api <absolute-http(s)-URL>`。
  - `--base-url` 只合并更新 `credentials.base_url`，不会重置 API key、模型映射、池模式或其他凭据字段。
  - Anthropic API-key 的地址应填写供应商 origin；网关会自行拼接 `/v1/messages`，不要把 `/v1` 再写入地址。
  - `--groups` 整表替换全部分组，并重写切号模板。
  - 已启用探活账号的私有分组必须列入；隔离后的收回顺序只见
    `references/upstream-scheduling.md`。
- 创建上游必须显式传入实时读取解析出的 `--groups <id,id,...>`。
  - 不使用固定分组默认值，避免平台或作用域误绑。
  - URL 参数规则只见“运行面与排队诊断”。
- 多个同充值地址 API Key 只对实际充值动作记一笔充值；余额共享钱包、账号投影和写入范围见
  [额度监控](references/quota-monitoring.md) 与 [上游与调度](references/upstream-scheduling.md)。
- 收入、采购、充值、退款和毛利读取 `references/accounting.md`。
- 手工收入明细使用 `cash ledger --period YYYY-MM --over-api <absolute-http(s)-URL>`，汇总使用 `profit daily`。
- BugTeam 客户 API 使用 `bugteam` CLI 命令组，配置中的 `bugTeam.customerToken`、`customerAccount`、`customerPassword` 只能引用仓库外 Secret：
  - 只读：`bugteam login`、`balance`、`inventory --product <id> --quantity N`、`shelves --product <id>`、`pickup order-status --id <id>`、`recoveries list`。
  - 实时成本：`bugteam cost-monitor get --over-api <absolute-http(s)-URL>` 读取最新摘要，显式增加 `--include-records` 才展开 6 小时历史；`bugteam cost-monitor sample --over-api <absolute-http(s)-URL>` 提交一次采样，并用返回的 workflow ID 查询原作业。
  - 订单：`pickup order-create --product <id> --quantity N [--idempotency-key <key>]`；创建必须 `--confirm`，超时不得重复下单。
  - 履约：`pickup download --id <id> --format sub2|cpa --output <path>`、`pickup push --id <id> --hub-id <id> --confirm`、`pickup take --id <id> --confirm`。
  - 401 修复：`recoveries claim --id <id> --ticket-stdin --output <path> --confirm`，Ticket 从 stdin 读取，必须复用同一 `--idempotency-key` 进行重试。
  - 余额兑换：`redeem --code-stdin --confirm`，CDK 不得出现在 argv、日志或输出中。
  - 一键购买导入：先用 `bugteam purchase-import options --over-api <absolute-http(s)-URL>` 回读默认值；
    再用 `bugteam purchase-import create --quantity N --confirm --over-api <absolute-http(s)-URL>` 提交，
    并只用 `bugteam purchase-import status --id <job-id> --over-api <absolute-http(s)-URL>` 跟踪原作业。
  - 下载和领取只输出路径、字节数、SHA256 与版本摘要，绝不输出账号 JSON、Token 或 Ticket。
- 30d.team 公开兑换找回使用独立的 `bugteam public-recovery` 命令组，不读取或发送 BugTeam 客户 Token：
  - 健康检查：`bugteam public-recovery health --base-url https://30d.team --card-code-stdin`。
  - 401 找回：先不带 `--confirm` 查看计划，再追加 `--confirm` 和 `--mode 401` 执行；兑换码只能经 stdin 输入。
  - 状态查询：`bugteam public-recovery status --base-url https://30d.team --card-code-stdin`，只输出脱敏状态，不输出下载 Token。
  - 下载：`bugteam public-recovery download --base-url https://30d.team --card-code-stdin --output <path>`；先查询可下载任务，成功后原子写入并返回字节数与 SHA256，已存在目标文件会拒绝覆盖。
  - `--base-url` 必须是无凭据、无路径、无查询和无片段的 HTTPS origin；该公开服务与 Api2Business 客户 API、Sub2API 本体均保持边界分离。
  - 完整复活作业使用 `start --account-id <Sub2API账号ID> --confirm` 创建并冻结原 OpenAI OAuth 账号配置，不读取兑换码、不启动 worker；原账号不删除，新复活账号固定按 `¥0.01` 成本导入。
  - 后续每次 `continue --id <job-id> --confirm` 只推进一个阶段；`health`、`reclaim`、`status` 和 `download` 阶段才追加 `--card-code-stdin`。
  - 新副本继承冻结的优先级、并发、负载因子、计费倍率、分组、代理、过期暂停、状态和调度开关；`verify` 只核对新副本，任一字段不一致即失败。
  - 已有下载文件需要补导入时使用 `import --account-id <原OAuth账号ID> --file <JSON> --plan-type <type> --confirm`；该入口保留原账号并创建独立复活副本。
  - 作业 ID、阶段、错误和脱敏日志保存在 `.state/public-recovery/<job-id>.json`；使用 `status` 查看摘要，使用 `logs --id <job-id> --limit N` 查看最近日志。
  - 作业失败后使用 `continue --id <job-id> --confirm` 从失败阶段继续，或使用 `retry --id <job-id> --stage <stage> --confirm` 单步重试；需要公开接口的阶段再次使用 `--card-code-stdin`，兑换码不落盘。
  - 完整复活导入显式使用 `cutoffTrigger=public-recovery` 和独立重复导入语义，保留原 OAuth 账号并创建新的复活账号；不会触发 OpenAI OAuth 导入后的 API-key 上游切断。
- 错误聚合与诊断：
  - `--group` 按错误记录的实际请求分组筛选；
  - 默认排除内部 monitor 用户和 `api2business-probe-*` 探活流量；
  - 返回 `groupFilterBasis=request-group` 与 `probeNoiseExcluded=true` 供调用方核对口径。
- 页面普通读取、V2 读模型缓存、额度缓存和刷新终态分别见
  [上游与调度](references/upstream-scheduling.md) 与
  [额度监控](references/quota-monitoring.md)；本技能不复制第二套缓存状态机。
- 任务收口必须同时执行 `bun run check` 和 `bun test`；运行时测试通过不能替代严格
  TypeScript 检查。类型修复应补充真实返回类型、可选字段默认值和测试夹具注解，不得通过
  关闭 `strict`、排除测试或静默断言来掩盖错误。
- 提交前使用 `git diff --check`、配置校验和部署校验；未归属的并行工作区文件不得加入提交，
  只有完成语义合并并通过对应验证后才清理。
- 读取失败、共享钱包回退和缺失状态的唯一口径见 [额度监控](references/quota-monitoring.md)；
  本技能不另定义缓存状态机。
- 共享钱包单轮余额采集、真实来源时间与冲突自动修复也只见
  [额度监控](references/quota-monitoring.md#共享钱包别名与跨作用域读取)。
- Sub2API 业务查询统一通过 Api2Business 排队 broker 读取 NC01 本地专用库；
  CLI、Web、worker 和人工脚本不得直连旧 PK01 数据库。
- 账号级代理默认策略：OAuth 导入、Plus/Team 账号和 API-key 上游默认直连，不绑定
  Sub2API Proxy；配置中的 `sourceProxyId: 0`、`proxyId: 0` 表示无代理。
- 只有用户显式选择并且 owning 配置允许时才启用账号级代理；这不影响 NC01 host-Docker
  的出网代理配置。
- 账号导入成功后异步触发一次 OAuth 实时成本采样；该采样独立于导入作业，不延长导入终态，失败只作为采样作业失败记录。
- 账号导入成功后不再自动提交 API-key 切断作业；API-key 切断仅保留显式手动入口。
- 手动验证同一采样路径使用 `accounts oauth-runtime-sample --over-api <absolute-http(s)-URL>`，返回独立 Temporal workflow ID。
- 上游智商评测：
  - 提交：`upstreams benchmark --id <account-id> --model <model> --confirm --over-api <absolute-http(s)-URL>`；
  - 进度与日志：`upstreams benchmark-status --id <benchmark-run-id> --over-api <absolute-http(s)-URL>`；
  - 账号历史：`upstreams benchmark-history --id <account-id> --limit 20 --over-api <absolute-http(s)-URL>`；
  - 评测只复用持久化探活专用 API Key，不读取供应商原始 Key，也不轮换探活 Key。
- 上游模型同步使用 `upstreams models sync --accounts <id-or-range,...> --confirm --over-api <absolute-http(s)-URL>`；
  读取、原生 bulk merge、单账号失败边界和写后回读唯一见
  [上游与调度](references/upstream-scheduling.md)。
- V2 作用域模型同步使用以下 CLI：
  - `upstream-scheduling-v2 model-sync plan --scope <codex|claude|grok> --over-api <absolute-http(s)-URL>` 只读生成下一批计划；
  - `upstream-scheduling-v2 model-sync run --scope <scope> [--accounts <id,...>] --confirm --over-api <absolute-http(s)-URL>` 执行手动批次；
  - `upstream-scheduling-v2 model-sync history --scope <scope> --over-api <absolute-http(s)-URL>` 查询轮次和账号明细。
  - 自动批次上限和间隔由 `operations.upstreamSchedulingV2.modelSync` 配置；自动开关只认各作用域的 `features.modelSyncAutomation`，每批最多 10 个，上一批完成后开始计时。
- V2 模型同步保留父轮次和账号明细记录；批次边界、失败隔离和游标语义唯一见
  [上游与调度](references/upstream-scheduling.md)。
- 评分与产出分母继续使用 `total_cost`。
- 额度监控的供应商实际支出、余额缓存、缺失处理和首屏测量唯一见
  [额度监控](references/quota-monitoring.md)。
- 首屏性能测量使用 `upstreams quota-monitor measure --mode snapshot|source --rounds N --over-api <absolute-http(s)-URL>`；
  `snapshot` 测缓存读模型，`source` 对照页面依赖链，输出只含耗时摘要，不展开账号或 Secret。

## 验收

- 验证 `/health`、Web 登录、主要数据页和至少一个异步作业。
- 页面截图使用正式 CLI 取得临时 session，再交给受控 WebProbe：

  ```bash
  bun skills/api2business/scripts/api2business-cli.ts \
    --config config/api2business.yaml \
    --over-api <absolute-http(s)-URL> \
    web screenshot \
    --profile upstream-scheduling-v2 \
    --scope grok
  ```

- `--scope` 可选，只接受 owning YAML 中已启用的 `codex`、`claude` 或 `grok` 作用域；CLI 将其写入
  V2 深链查询参数，并在 stderr 输出带 profile、scope 和 phase 的短进度行，避免临时脚本拼接 URL
  或长时间无输出。省略时使用配置中的默认作用域。
- 连拍复用 `web screenshot`。
  - `web screenshot --help` 直接显示本操作参数，不要求配置或重印完整 catalog。
  - `--burst-count 1..30` 和 `--burst-interval 200ms..10s` 控制同页采集。
  - 多帧时使用 profile 的桌面视口；单帧保持桌面与移动视口采集。
  - `--manifest <绝对路径>` 留存完整原始事件，默认回执保留有界失败请求。
  - 采集期间每五秒输出 profile、scope、phase 和耗时。
- `--session-ttl-seconds <正整数>` 显式创建独立的短时效验收会话。
  - 期限必须短于 `webAuth.sessionTtlSeconds`；省略时使用正式登录 API 返回的会话。
  - 先通过正式 `/api/login` 认证，再从 owning Secret source 读取签名材料。
  - 复用原生认证函数，不修改部署配置或其他用户会话。
  - 失效复验和正反经验见
    [Web 登录态与失效复验](../../docs/reference/web-authentication.md)。

```bash
bun skills/api2business/scripts/api2business-cli.ts \
  --config config/api2business.yaml --over-api <absolute-http(s)-URL> \
  web screenshot --profile upstream-scheduling-v2 --scope codex \
  --session-ttl-seconds 20 --burst-count 10 --burst-interval 5s \
  --manifest /absolute/path/session-expiry.json
```

- CLI 通过 `/api/login` 获取 Cookie，并只在内存中传给 WebProbe；WebProbe 不填写登录表单，Cookie 不进入 argv、日志、报告或磁盘。
- 需要把负余额或分页结果移入截图时，用 `--click-selector` 点击既有排序或分页控件。
  - V2 排序表头须带 `[data-sort-bound="1"]`，等待交互绑定后再点。
  - 例如人民币余额排序使用 `'#v2-account-table [data-sort-key="balance"][data-sort-bound="1"]'`。
  - 静态表头先于脚本出现，过早点中不会改变排序；采集成功不代表点击生效。
  - 此参数只辅助取景，是否符合验收目标仍须人工看图。
- 验证重启后账本、缓存、采样和作业状态仍可读取。
- 失败时按配置、Secret、网络、数据库、worker 和外部 API 的顺序定位首个断点。

## 固定窗口巡检与 SLO

- 两系统独立 SLO、broker 新鲜度、共享钱包与成本覆盖走
  [固定窗口巡检](references/observability.md)。
- `observability costs --over-api <absolute-http(s)-URL>` 独立读取七天逐日成本和钱包余额。
  - 同时返回精确的滚动 24 小时成本，供近期消耗预算使用。
  - 不完整成本保留已知部分；充值风险判断边界见上述参考。
