## 受保护手动账号代理与分组绑定

Sub2API 管理 UI 的账号连接测试使用账号级 `ProxyID` / proxy URL 配置上游 HTTP transport；账号没有绑定 proxy 时会直接出站，即使 Sub2API Pod 已经有 `HTTP_PROXY` / `HTTPS_PROXY` 环境变量。看到 WebUI 账号测试连 `chatgpt.com` 超时、但 Pod 内显式走目标 proxy 可通时，先检查该账号是否属于 `manualAccounts.protected` 并声明了 `proxyBinding`。如果同一账号用 `gpt-5.2-pro` 返回 ChatGPT OAuth 不支持 Codex 的模型能力错误，但默认/受支持模型能完成 `hi` 或 `/v1/responses` smoke，这不是代理失败；按模型映射/账号能力另行处理。

如果 WebUI 账号连接测试显示 `proxyconnect tcp: dial tcp 127.0.0.1:<port>: connect: connection refused`，先确认该 proxy URL 是账号级 loopback 配置：在 k3s target 内，`127.0.0.1` 是 Sub2API Pod 自己，不是节点或 PK01。不要先改账号凭据、PK01 Caddy、`api.pikapython.com` 或统一 key；应在目标 `config/platform-infra/sub2api.yaml` 声明 `targets[].accountLocalProxy`，由 `platform-infra sub2api apply --target <id>` 渲染同 Pod sidecar 和 Secret，再用 `validate --target <id>` 的 `accountLocalProxy` 探针验证 `http://127.0.0.1:<port>`。输出仍只允许披露 sourceRef、fingerprint、secretName 和 proxyUrl，不打印 proxy 密码或生成配置。

多个 Sub2API target 共享数据库时，账号临时不可调度状态也是共享状态，管理页所在 target 不等于写入故障状态的 target。遇到上述 loopback 拒绝时，先从 `config/platform-infra/sub2api.yaml` 读取全部 active target，并分别执行一次 `validate --target <id>`；只修复 `accountLocalProxy` 探针失败或缺失的 target，不修改健康 target 的主机代理、账号凭据或临时不可调度模板。恢复以三个信号为准：

- 故障 target 的 `accountLocalProxy.probe.failureFamily=ok`；
- 从同一 target 公网入口执行原生账号连接测试成功；
- 任一共享管理视图读取该账号均显示 `temp-unschedulable active=false`。

WebUI 账号连接测试也不经过统一消费 API key 的 pool group 选择器；账号测试正常不代表 PC Codex 客户端能选中该账号。看到 WebUI 账号测试正常、但 `/responses` 或 `/v1/responses` 以 `account-select-failed` / `no available accounts` 返回 503 时，先检查该手动账号是否声明了 `groupBinding.source: pool-group`，并确认 Sub2API `account_groups` join 里存在该账号与当前统一 API key `group_id` 的绑定。对 k3s target 和 PK01 host-Docker target，都通过 `codex-pool sync --target <target-id> --confirm` 把受保护手动账号加入当前 `pool.groupName`；PK01 走 host-Docker adapter，不使用 k8s Secret/CronJob。证据只输出 account id、group id、presence/fingerprint 和 smoke 状态，不打印密钥。

受保护手动账号仍由人工在 Sub2API UI 维护 credentials/status 等字段；UniDesk 只允许通过 YAML 做代理和分组窄绑定：

```bash
bun scripts/cli.ts platform-infra sub2api codex-pool plan --target <target-id>
bun scripts/cli.ts platform-infra sub2api codex-pool sync --target <target-id> --confirm
bun scripts/cli.ts platform-infra sub2api codex-pool validate --target <target-id>
```

`manualAccounts.protected[].targetIds` 是账号保护和窄同步的 target 作用域。省略时该手动账号在所有 target 上都受保护；设置如 `[PK01]` 时，JD01/D601 等其他 target 的 `codex-pool sync --confirm`、`validate` 和 `sentinel-probe` 不再把这个手动账号纳入当前运行面要求。不要通过自动删除不在 YAML 的账号来解决漂移；只增/改 YAML 控制的账号，未被当前 target 的 YAML 控制的账号保持人工所有权。

`sync` 输出应显示 `manualAccounts.ok=true`、`proxySync.ok=true`、`groupSync.ok=true`，且该账号的 proxy/group `bindingAligned=true`。`sentinel-probe --account <manual-account> --confirm` 对受保护手动账号必须继续拒绝，通常返回 `account-protected-manual`；不要为了测试而把该账号移入 `profiles.entries` 或取消保护。需要证明 WebUI 同款账号测试恢复时，用 Sub2API admin account test 原入口测最小 `hi` 和默认/受支持模型，并只记录 account id、proxy id、event types、HTTP status 和短 output preview，不记录 OAuth token 或 Secret 明文。若指定模型返回 “model is not supported when using Codex with a ChatGPT account” 一类能力错误，先归因到模型能力/映射，而不是 proxy。

如果 `manualAccounts.protected` 中声明的账号在当前 Sub2API 运行面已经不存在，`codex-pool sync --confirm` / `validate` 会把 `manualAccounts.ok=false`、`proxySync.action=account-missing` 或 `groupSync.action=account-missing` 作为整体失败项。这是手动账号漂移，不是 YAML-managed pool 账号创建失败；不要自动创建、删除、接管或从 YAML 移除该手动账号。先确认账号所有权：需要继续保护时由人工在 Sub2API UI 恢复同名账号，再跑 sync 对齐 proxy/group；确认退役时再按明确决策修改 `manualAccounts.protected`。对同一次新增的 YAML-managed 上游，可用该账号自己的 `sentinel-probe --account <accountName> --confirm`、`sentinel-report` 和 `trace` 作为窄验收证据，并把手动账号漂移单独登记。
