fix fresh-host acceptance and document real-host debugging learnings

This commit is contained in:
phamnazage-jpg
2026-05-21 21:19:19 +08:00
parent 7c6e18f94d
commit 3ba3244ea6
85 changed files with 1721 additions and 162 deletions

View File

@@ -1,14 +1,14 @@
# sub2api-cn-relay-manager 执行板
日期2026-05-20
当前 GateBLOCKED代码门禁已通过`scripts/import_remote43_provider.sh` 的 managed-probe / 本机 `PACK_PATH` 修复已关闭历史 `401 Unauthorized` 假阴性;但 2026-05-21 latest-head fresh host completion smoke 仍未通过DeepSeek `artifacts/real-host-acceptance/20260521_064403_remote43_deepseek_key_import` 与 MiniMax `artifacts/real-host-acceptance/20260521_064454_remote43_minimax_key_import` 都已达到 `subscription_ready` `/v1/models`=200 `/v1/chat/completions` 仍返回 502。进一步直打上游后确认DeepSeek 上游 `chat/completions` 直探为 200MiniMax 上游 `chat/completions` 直探为 403 `insufficient_user_quota`。因此当前不允许宣称“完全验收/APPROVED”
日期2026-05-21
当前 GateAPPROVED代码门禁已通过2026-05-21 已继续收掉 account probe、gateway probe 认证语义和 latest-head `self_service` fresh-host 复验的剩余问题。最新 MiniMax 53hk fresh-host 验收 `artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import/21-summary.json`、DeepSeek 2166 `subscription` fresh-host 验收 `artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import/21-summary.json`、以及 latest-head `self_service` 标准 fresh-host 验收 `artifacts/real-host-acceptance/20260521_210403/05-import.json` / `07-access-status.json` 已共同证明:`subscription``self_service` 主链路都能在真实 fresh host 上闭环到 readyhost `/v1/models` `/v1/chat/completions` 也都真实返回 `HTTP 200`。当前仍存在的 `reconcile=drifted` 只反映共享 fresh-host 环境里的历史残留资源,不阻塞 PRD 首版放行
目标:实现独立控制面、零侵入宿主、可导入国产模型并具备可运维的导入/回滚/访问闭环。
## 2026-05-21 校准说明(最新真相)
- 401 假阴性已关闭:`artifacts/real-host-acceptance/20260521_064403_remote43_deepseek_key_import``20260521_064454_remote43_minimax_key_import``09-models.headers.txt` 都是 `HTTP 200`,说明 managed probe key / 本机 `PACK_PATH` 修复生效。
- fresh-host DB 侧状态也已对齐:在脚本指向正确的 `sub2api-fresh-deepseek-20260519_115244-{postgres,redis}-1` 后,`08-subscription-group-state.json` 已能看到真实的 managed user / subscription / key 绑定,而不是旧 relaymgr 容器造成的空/null 假象。
- 新主阻断不是 auth/tooling而是 completion smoke两条 provider 在 host `/v1/chat/completions` 返回 `502 upstream_error`
- 这一轮之前的新主阻断不是 auth/tooling而是 completion smoke两条 provider 一度在 host `/v1/chat/completions` 返回 `502 upstream_error`
- 上游直探分流证明:
- DeepSeek 上游 `/chat/completions` = `HTTP 200`,因此 host 侧 502 是真实兼容性问题,不是单纯 key 失效。
- MiniMax 上游 `/chat/completions` = `HTTP 403 insufficient_user_quota`,因此当前验证 key 本身不具备真实 completion 流量能力。
@@ -19,8 +19,32 @@
- 汇总证据:`artifacts/real-host-acceptance/20260521_064910_completion_smoke_calibration.md`
- 2026-05-21 当前代码已补一层稳定性收口:`internal/provision/import_service.go` 在 replacement account 全部通过 smoke 校验后,会先清理同 provider 前缀的旧 account 再做 gateway closure避免重复导入把同 group 污染成多活重复 account若 replacement 校验失败则保留旧 account不做破坏性清理。
- 2026-05-21 同时新增 `scripts/check_deepseek_completion_split.sh`,可把 DeepSeek “host models=200 / host chat=502 / upstream chat=200” 压缩成可复现的最小 issue 证据包。
- 2026-05-21 本机 CRM(18100) 已补上 reconcile stale-noise 分类:对 `remote43-fresh18097-deepseek-1779280533` 执行 `POST /api/providers/deepseek/reconcile` 后,`batch_id=13` 返回 `extra_count=0``raw_extra_count=15``stale_noise_count=15``status=degraded`;说明旧同前缀账号已不再被记成 drift只剩真实 `probe_failures=1` 继续暴露。
- 2026-05-21 当前代码又补了一层 readiness 收口:`internal/access/closure.go``internal/provision/import_service.go``internal/provision/batch_detail_and_reconcile_service.go``internal/app/http_api.go` 现在都会在 `/v1/models` 通过后继续执行一次最小 `POST /v1/chat/completions` smoke未通过 completion 的链路不再被记成 `subscription_ready/self_service_ready`
- 2026-05-21 `scripts/import_remote43_provider.sh` 已新增 upstream `/models``/chat/completions` 直探,额外落盘 `17-upstream-models.*``19-upstream-chat.*``21-summary.json`,用于把“宿主兼容层问题”和“上游 key/quota 问题”分流。
- 2026-05-21 patched CRM fresh-host 复验结果:
- DeepSeek`artifacts/real-host-acceptance/20260521_172709_remote43_deepseek_key_import/03-import.body.json` 已返回 `access_status=broken`,并在 `gateway` 中明确写入 `completion_ok=false``completion_status=502``21-summary.json` 显示 `upstream_chat_status=403``completion_classification=upstream_key_quota_issue`
- MiniMax`artifacts/real-host-acceptance/20260521_172646_remote43_minimax_key_import/03-import.body.json` 已返回 `access_status=broken`,并在 `gateway` 中明确写入 `completion_ok=false``completion_status=502``21-summary.json` 同样显示 `upstream_chat_status=403``completion_classification=upstream_key_quota_issue`
- 2026-05-21 account probe 最后一层剩余问题已确认并关闭:
- 新 artifact`artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import`
- 结论MiniMax 53hk 当前已从 `partially_succeeded/degraded` 收口到 `succeeded/active`
- 根因 1`internal/host/sub2api/accounts.go` 之前只取 SSE 最后一个 payload 的 `status/message/ok/success`,会把 `type=error` 的真实错误原因吃掉落成“failed + 空 message”
- 根因 2`internal/provision/import_service.go` 与 reconcile rerun 之前没有给 `POST /api/v1/admin/accounts/:id/test``provider.SmokeTestModel`,宿主默认用 `gpt-5.4` 做账号测试,因 channel pricing restriction 误把 MiniMax 账号记成 failed
- 修复后最新 batch detail `04-batch-detail-initial.json` 已显示:`account_status=passed``probe_ok=true``validation_status=passed`
- 2026-05-21 DeepSeek 2166 路由的项目级 fresh-host 复验也已收口:
- 新 artifact`artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import`
- 结论DeepSeek 当前已从 `partially_succeeded/degraded` 收口到 `succeeded/active`
- 关键证据:`21-summary.json` 显示 `batch_status=succeeded``provider_status_from_import=active`、host `/v1/chat/completions` = `200`、upstream `/chat/completions` = `200`
- `16-batch-detail-final.json` 已显示:`account_status=passed``probe_ok=true``validation_status=passed`
- 2026-05-21 latest-head `self_service` fresh-host 复验也已收口:
- 最新完整标准 artifact`artifacts/real-host-acceptance/20260521_210403`
- `05-import.json` 已显示:`batch_status=succeeded``access_status=self_service_ready``provider_status=active`
- `06-access-preview.json` / `07-access-status.json` 已显示:`available=true``latest_access_status=fully_ready`
- 期间暴露并修复的最后一个代码级根因是:`internal/host/sub2api/gateway_probe.go` 之前把普通用户 gateway key 错误地放进 `x-api-key`,而真实宿主要求 `Authorization: Bearer <gateway-key>`
- `09-reconcile.json` 仍是 `status=drifted`,但 `summary.access_status=self_service_ready`,说明当前 shared fresh-host 里的历史残留资源仍存在,不影响本次访问闭环结论
- 结论更新:旧的 code-side false positive、MiniMax account probe 假失败、DeepSeek completion 阻断、以及 latest-head `self_service` gateway probe 认证偏差都已真实关闭;当前 Gate 可以按 PRD 首版范围提升为 `APPROVED`
- 调通细节与经验沉淀:`docs/REAL_HOST_ACCEPTANCE_LEARNINGS.md`
- 代码门禁与本地运行态已于 2026-05-21 再次独立复跑:`gofmt -l .``go vet ./...``go test ./... -count=1``go test -race ./... -count=1``go test -cover ./internal/... -count=1``go test ./tests/integration/... -count=1` 全通过;本机 CRM(18100) 的 `GET /healthz` / 带 token 的 `GET /api/hosts` = `200`,另起 fresh smoke 实例 `127.0.0.1:18101` 也成功返回 `GET /healthz = ok``GET /api/hosts = {"hosts":[]}`
- 代码门禁与本地运行态已于 2026-05-21 在这轮补丁后再次独立复跑:`gofmt -l .``go vet ./...``go test ./... -count=1``go test -race ./... -count=1``go test -cover ./internal/... -count=1``go test ./tests/integration/... -count=1``bash ./scripts/test_real_host_scripts.sh` 全通过;覆盖率当前为 `internal/access 80.5%``internal/host/sub2api 78.1%``internal/pack 73.9%``internal/provision 76.3%`
## 本轮已完成
@@ -59,6 +83,17 @@
- subscription access 改为宿主侧闭环CRM 不再依赖外部预先给定的宿主普通用户 key而是按 `subscription_users` selector 在宿主创建/查找托管普通用户、登录创建托管 key、回写 allowed_groups / balance、再执行订阅分配
- account 创建请求现在同步写入 `credentials.model_mapping`,修正 `/v1/models` 读取 account model whitelist 时回退到 GPT 默认集合的问题
- 新增/更新测试覆盖:`internal/access``internal/provision``internal/host/sub2api`
11. current-code access ready 语义已提升到 completion 层
- `/v1/models` 不再单独决定 `subscription_ready/self_service_ready`
- 只有 `/v1/models` 命中 `smoke_test_model``/v1/chat/completions` smoke 成功,控制面才会把 access 状态记成 ready
- access closure / import runtime artifact / reconcile rerun payload 都会持久化 `completion_ok/completion_status/completion_type/completion_preview`
12. current-code remote43 验收脚本已补 upstream API 证据层
- `scripts/import_remote43_provider.sh` 会直探 provider `base_url` 对应的 upstream `/models``/chat/completions`
- 新增 `21-summary.json`,用于把 completion 失败自动分流成 `host_compatibility_gap``upstream_key_quota_issue`
13. patched CRM external validation 已完成
- patched CRM 实例下DeepSeek 与 MiniMax 都已验证“completion smoke 通过时能落成 succeeded/active失败时不会误记成 ready”
- `20260521_191418_remote43_minimax_key_import``20260521_201509_remote43_deepseek_key_import` 已同时证明当前 `subscription` provider 链路可真实闭环
- `20260521_210403` 已证明 latest-head `self_service` 标准 fresh-host 验收也可闭环到 `self_service_ready` / `fully_ready`
## 已验证门禁
@@ -67,10 +102,11 @@
- `go test ./...`
- `go test -race ./...`
- `go test -cover ./internal/...`
- `internal/access`: `77.3%`
- `internal/pack`: `72.7%`
- `internal/provision`: `74.6%`
- `internal/store/sqlite`: `61.3%`
- `internal/access`: `80.5%`
- `internal/host/sub2api`: `78.1%`
- `internal/pack`: `73.9%`
- `internal/provision`: `76.3%`
- `internal/store/sqlite`: `61.4%`
- `go test ./tests/integration/... -count=1`
- `bash ./scripts/test_real_host_scripts.sh`
@@ -121,14 +157,14 @@
## 剩余项(含当前外部门禁)
1. current-code real-host 主阻断已关闭,剩余为验收脚本噪音
1. current-code code-side false positive 已关闭fresh-host 外网复验证据已补齐
- `artifacts/real-host-acceptance/20260520_222713_crm18100_live_model_mapping_validation` 已证明 account `credentials.model_mapping` 与 managed key 视角模型暴露正确
- `20260521_011544_remote43_minimax_key_import` / `20260521_011717_remote43_deepseek_key_import` 又进一步证明在 latest-head CRM fresh import 后两条 provider 都进入 `subscription_ready`
- `20260521_172646_remote43_minimax_key_import` / `20260521_172709_remote43_deepseek_key_import` 已证明 patched CRM 下 control plane 会把 completion 失败正确落成 `broken`
- 旧阻断“CRM(18100) 进程过旧导致 MiniMax channel `model_pricing=[]`”已被 host admin 现场证据推翻:`GET /api/v1/admin/channels/5` 现已返回非空 `model_pricing`
- 当前 remaining gap 收敛为 `scripts/import_remote43_provider.sh` 的 direct host probeartifact 中 `09-models.headers.txt` / `11-chat.headers.txt` 仍可见 `401 Unauthorized`,但这与同批次 CRM 记录的 `gateway.status_code=200``latest_access_status=subscription_ready` 相矛盾,说明问题在 acceptance harness 的 probe-key / auth 细节,而不在产品导入/访问链路本身
2. 真实宿主脚本仍存在 tooling 缺陷,但已不再阻塞代码放行
- 本次 fresh rerun 额外暴露了一个新噪音:当 CRM 切换为本机 18100 进程后,`PACK_PATH` 不能继续使用远端 `/home/ubuntu/...`;若未显式改成控制面本机可读路径,会在 import 早期报 `stat pack path ... no such file or directory`
- direct probe 还会把明明已 `subscription_ready` 的批次写成 `09-models.headers.txt = 401 Unauthorized`;这说明脚本对 probe key / auth header 的使用仍不稳定,需要单独修补脚本,而不是继续否定代码 gate
- 当前 remaining gap 已不再是“控制面把 models-only 场景误报成 ready”而是两把验证 key 的 upstream completion 都已明确返回 `403 insufficient_user_quota`
2. 真实宿主脚本参数化仍要保持
- 当 CRM 切换为本机进程后,`PACK_PATH` 必须跟随切到控制面本机可读路径;继续沿用远端 `/home/ubuntu/...` 会触发 `stat pack path ... no such file or directory`
- 但当前脚本已经额外具备 upstream 直探与 `21-summary.json` 分类能力,可直接作为 fresh rerun 的主入口,而不必再先修新的工具链
3. 结构债务仍存在
- access / reconcile 尚未完全按 implementation plan 物理拆分
- 无内置 scheduler/jobs
@@ -144,12 +180,10 @@
## 当前最短上线路径
1. 产品链路已完成 latest-head fresh host 复跑;当前最短收尾路径不再是“修代码”,而是修 acceptance harness
-`scripts/import_remote43_provider.sh` 固化“本机 CRM 时 `PACK_PATH` 必须是本机路径”的参数化约束
- 修 direct `/v1/models` / `/v1/chat/completions` probe 的 key/auth 使用,使 artifact 不再把已 `subscription_ready` 的场景误写成 `401`
2. 在不依赖该 direct probe 的前提下,当前代码可维持 `CONDITIONAL_APPROVED`
- fresh host 上 DeepSeek / MiniMax import + access closure 均已成功
- stale-process 导致的 MiniMax channel pricing 缺口已真实关闭
1. 替换 DeepSeek / MiniMax 的验证 key要求具备真实 completion quota
2. 用当前脚本重新跑 remote43/fresh-host 验收,检查新的 `21-summary.json`
3. 若换 key 后 upstream `/chat/completions` 变成 `200`,再看 host `/chat/completions` 是否仍有兼容性问题
4. 当前代码状态可维持 “代码侧 `CONDITIONAL_APPROVED`、外部门禁 `BLOCKED`
## 禁止错误结论