## 账号池排障

- Codex pool 哨兵、账号冻结/恢复、marker-only 判断或 probe 周期看不清：第一步跑 `bun scripts/cli.ts platform-infra sub2api codex-pool sentinel-report`。这个报表是主观察面；只有报表缺字段或需要底层证据时，才继续看 `--raw`、CronJob log、state ConfigMap 或 Sub2API 管理 UI。若看到“临时不可调度状态”且包含规则序号/匹配关键词，检查 Sub2API `account_temp_unschedulable` 日志和账号 `temp_unschedulable_*` 字段；sentinel 只解释 `schedulable=false` 的 active quarantine，不解释这类内置临时冷却。
- 只加强监控、不让哨兵自动冻结账号时，把 YAML `sentinel.actions.enabled=false` 后 `codex-pool sync --confirm`。此时 marker probe 和 gateway failure monitor 仍记录 `would-freeze` / observe-only 证据，但不会通过 Sub2API admin 写 `schedulable=false`；`/responses/compact` 的 `codex.remote_compact.failed` 和 compact 上游 5xx failover 只作为 `gateway-compact-*` 观察事件记录，不作为哨兵自动切换触发器。
- 单个 request id 报 502/503/中断/没有自动切号：第一步跑 `bun scripts/cli.ts platform-infra sub2api codex-pool trace --request-id <requestId>`。先看 `outcome`、`reason`、`FAILOVER`、`SELECT-FAILED`、`ACCOUNT SIGNALS` 和 `WINDOW STATS`；只有 trace 报表缺字段或需要审计原始日志时，才加 `--show-lines` 或 `--raw`。若 `reason=failover-attempted-no-candidate`，说明切号动作已发生，但 scheduler 在排除失败账号后没有可用候选；继续用 `sentinel-report` 和 `validate --full` 区分 sentinel quarantine、request-path temp-unschedulable、账号 status 或容量耗尽。
- profile invalid：先修 `~/.codex/config.toml.<profile>` 的 `base_url`、`wire_api`、`model` 或 `auth.json.<profile>` 的 API key；不要在 YAML 中写密钥。
- 手动 OAuth/API-key 账号的 WebUI account test 连 `chatgpt.com` 超时，但目标运行面显式 HTTP proxy 探针可通：不要只看 Pod 或容器环境变量，按“受保护手动账号代理与分组绑定”小节确认 `manualAccounts.protected[].proxyBinding`，跑 `codex-pool sync --target <id> --confirm` 后再用原账号测试复测。若复测不再 reset/timeout，而是 `gpt-5.2-pro` 这类指定模型返回 ChatGPT OAuth Codex 不支持的能力错误，用默认/受支持模型或统一 key smoke 验证代理，不要把模型错误当作代理仍坏。
- 手动 OAuth/API-key 账号 WebUI account test 正常，但 PC Codex 客户端通过统一 key 访问 `/responses` 返回 503 且 trace 是 `account-select-failed` / `no available accounts`：按“受保护手动账号代理与分组绑定”小节确认该账号已绑定统一 key 使用的 pool group。WebUI group 列表和账号详情不一定足以证明 scheduler 可调度；必要时核对 admin account availability 与 `account_groups` join。k3s target 和 PK01 host-Docker target 都通过 `codex-pool sync --target <id> --confirm` 后用 `codex-pool validate --target <id> --full` 复测统一 key；如果 `MANUAL=N` 指向受保护手动账号缺失，先按账号所有权恢复或退役该手动账号，不把它混同为 YAML-managed pool 账号失败。
- pool key 401：跑 `codex-pool sync --confirm` 重建 Sub2API key 与 k3s Secret 绑定，再跑 `codex-pool validate`。
- pool key、admin password 或 k8s Secret `.data` 被 stdout、日志、issue 或本地 transcript 打印时，按泄露处理：撤销对应 Sub2API key 或 token，删除/重建受影响的 target Secret，通过 `codex-pool sync --target <id> --confirm` 或相应 YAML sourceRef 重新下发，再用 fingerprint、presence 和 `valuesPrinted=false` 作为 closeout 证据；不要复述旧值或新值。
- 运行中过去的验证探针残留：只用 `codex-pool cleanup-probes --confirm` 清理 `unidesk-probe-*` 临时资源；不要把真实 managed account 删除当作探针清理或可用性恢复。
- default profile 递归：检查 YAML default entry 是否使用 `*.pre-sub2api` 备份文件；必要时恢复备份后重新 `configure-local --confirm`。
- 上游需要 WebSocket v2：先做 direct Codex WSv2 probe；通过后才给该 profile 配 `openaiResponsesWebSocketsV2Mode: ctx_pool|passthrough` 并跑 `sync --confirm`；把它当 capability candidate，容量仍以 YAML 中的 `capacity` 或默认值为准。
- Codex 启动 WebSocket 回退：用原入口 Codex smoke 复现，再用 bounded Sub2API 日志确认 account；对 WS handshake 4xx/5xx、`openai.websocket_account_select_failed` 或 close-before-`response.completed` 的账号关闭 YAML WSv2 能力后同步。若没有剩余 WSv2-capable account，把 `localCodex.supportsWebSockets` 和 `localCodex.responsesWebSocketsV2` 一起关掉，不把临时可用性推断写成调度配置。
- 上游要求 Codex User-Agent：只给该 profile 配 `upstreamUserAgent`，跑 `sync --confirm`。
- 上游报 capacity/rate-limit/overload/Bad Gateway/Gateway Timeout 后没有隔离或频繁先失败再恢复：先看 `codex-pool sentinel-report` 的 marker、动作、冻结 TTL 和下一次 probe，也看 `codex-pool validate --full` 的 recent gateway failover/forward failure 证据；同时对照当前 Sub2API 源码里 `/v1/responses` handler、`Forward`、`shouldFailoverOpenAIUpstreamResponse` 和 `handleOpenAIAccountUpstreamError` 的真实传播路径。不要手动禁用账号、删除账号、改 membership/priority/capacity/loadFactor 或从 YAML 移除问题账号来替代通用 failover 与哨兵隔离/恢复。
- Codex 报 weekly-limit、`less than 10% of your weekly limit left`、`Run /status for a breakdown` 等账号状态/软配额提示并要求切号：不要把新关键词写成 Sub2API 内置临时不可调度策略来恢复可用性；由 marker-only 哨兵按非 marker 响应统一冻结，并用 `sentinel-report` / `sentinel-probe` 验证。
- 上游 400/503 响应体出现 `invalid_encrypted_content`、`bad_response_status_code`、`invalid_request_error` + 稳定 unsupported-model 文案、unsupported-model、`暂不支持` / `可用模型`、`model_not_found`、`No available channel for model ...` 或同类稳定模型路由 / Responses encrypted-content 兼容性失败：按通用 temp-unschedulable/failover 加哨兵 marker 证据处理，不用 account membership、priority、capacity、loadFactor、WebSocket mode、User-Agent 或 provider pinning 掩盖该错误族。
- 上游错误反复触发：`invalid_encrypted_content`、unsupported-model、`Recovered upstream error ...`、`Bad Gateway`、`Gateway Timeout`、Cloudflare `524`、Codex-facing `Upstream request failed`、`Unknown error`、`context deadline exceeded`、`context canceled`、`model_not_found`、`No available channel for model`、大上下文 `413` 和 `openai_error` 这类稳定包装文案，先确认 YAML temp-unschedulable 已同步、Sub2API 源码会把该错误族传播成 `UpstreamFailoverError`、运行日志出现 `openai.upstream_failover_switching`。若匹配规则后仍只看到 `openai.forward_failed`，根因是 Sub2API HTTP `/responses` 没把该错误传播成 `UpstreamFailoverError`，应修 Sub2API failover classifier/error propagation，不硬编码账号或给 `only` 特权。
- Codex auto compact 后丢上下文：先确认 YAML `localCodex` 是否声明启用 WSv2；若启用，再确认本机 `~/.codex/config.toml` 是否有 `supports_websockets = true` 和 `responses_websockets_v2 = true`，并看 `codex-pool validate` 的 WSv2 candidate 和 Sub2API 日志里的 `transport=responses_websockets_v2`。若 YAML 当前禁用 WSv2，则按 HTTP Responses 稳定性排查，不把旧 WS 口径当成验收要求。
- Codex smoke 有 reconnect/1013：这是上游并发/可用性问题，和 HTTP-only compact context-loss 分开处理；记录 session/log 证据并关联专项 issue，不要用运行时手补覆盖 YAML 容量。
