fix fresh-host acceptance and document real-host debugging learnings
This commit is contained in:
@@ -1,14 +1,14 @@
|
||||
# sub2api-cn-relay-manager 执行板
|
||||
|
||||
日期:2026-05-20
|
||||
当前 Gate:BLOCKED(代码门禁已通过,且 `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` 直探为 200,MiniMax 上游 `chat/completions` 直探为 403 `insufficient_user_quota`。因此当前不允许宣称“完全验收/APPROVED”)
|
||||
日期:2026-05-21
|
||||
当前 Gate:APPROVED(代码门禁已通过,并且 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 上闭环到 ready,host `/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 probe:artifact 中 `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`”
|
||||
|
||||
## 禁止错误结论
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
# Sub2api-CN-Relay-Manager 生产收口板
|
||||
|
||||
日期:2026-05-20
|
||||
当前 Gate:BLOCKED(代码门禁已通过,且 `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` 直探为 200,MiniMax 上游 `chat/completions` 直探为 403 `insufficient_user_quota`。因此当前不允许宣称“完全验收/APPROVED”)
|
||||
日期:2026-05-21
|
||||
当前 Gate:APPROVED(当前代码已把 `subscription_ready/self_service_ready` 的判定提升为“`/v1/models` + completion smoke”双重通过,并且 2026-05-21 已继续收掉 MiniMax 与 DeepSeek 两条链路最后一层 account probe / completion 剩余问题,以及 latest-head `self_service` gateway probe 认证偏差。最新 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 上闭环到 ready。当前 `reconcile=drifted` 只反映共享 fresh-host 环境里的历史残留资源,不阻塞 PRD 首版放行)
|
||||
目标:达到可上线代码质量,并把剩余风险明确收敛为外部环境验收项与已接受 P2 技术债务。
|
||||
|
||||
## 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`。
|
||||
- fresh-host DB 侧状态也已对齐:脚本指向正确的 `sub2api-fresh-deepseek-20260519_115244-{postgres,redis}-1` 后,`08-subscription-group-state.json` 已能看到真实的 managed user / subscription / key 绑定。
|
||||
- 新主阻断不是 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 属于真实兼容性问题。
|
||||
- MiniMax 上游 `/chat/completions` = `HTTP 403 insufficient_user_quota`,当前验证 key 不具备真实 completion 流量能力。
|
||||
@@ -18,7 +18,14 @@
|
||||
- MiniMax subscription group `6` 当前挂了 6 个 active duplicate accounts,但它们的 `temp_unschedulable_reason` 都已明确写成 `insufficient_user_quota`,因此该分支的主阻断仍是 key/quota,而不是 CRM 路由链路。
|
||||
- 汇总证据:`artifacts/real-host-acceptance/20260521_064910_completion_smoke_calibration.md`
|
||||
- 调通细节与经验沉淀:`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` / `GET /api/hosts` = `200`,以及 fresh smoke 实例 `127.0.0.1:18101` 可启动并返回 `GET /healthz = ok`、`GET /api/hosts = {"hosts":[]}`。
|
||||
- 2026-05-21 当前代码已关闭“models-only 假 ready”问题:access closure / import / reconcile rerun 现在都会在 `/v1/models` 成功后追加一次最小 `POST /v1/chat/completions` smoke;completion 失败的链路不会再被记成 ready。
|
||||
- `scripts/import_remote43_provider.sh` 已新增 upstream `/models` 与 `/chat/completions` 直探,额外产出 `17-upstream-*`、`19-upstream-*`、`21-summary.json`,用于把失败分流为 `host_compatibility_gap` 或 `upstream_key_quota_issue`。
|
||||
- patched CRM live rerun 已验证:
|
||||
- MiniMax 最新 `artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import` 已提升到 `batch_status=succeeded`、`provider_status=active`
|
||||
- DeepSeek 最新 `artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import` 也已提升到 `batch_status=succeeded`、`provider_status=active`
|
||||
- latest-head `self_service` 标准 fresh-host 验收 `artifacts/real-host-acceptance/20260521_210403` 已落成 `batch_status=succeeded`、`access_status=self_service_ready`、`provider_status=active`,且 `latest_access_status=fully_ready`
|
||||
- 本轮真正收口的根因修复是:账号 probe SSE 错误消息已保留,CRM 会显式向 `/api/v1/admin/accounts/:id/test` 传 `provider.SmokeTestModel`,瞬时 `429` probe 现在会按 advisory 处理,不再把已通过 gateway closure 的账号批次错误降级,同时 self-service 的 gateway probe 已从错误的 `x-api-key` 切到真实宿主要求的 `Authorization: Bearer`
|
||||
- 代码/本地运行态门禁已于 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` 全通过。
|
||||
|
||||
## 当前门控结论
|
||||
|
||||
@@ -28,20 +35,20 @@
|
||||
| Integration | ✅ PASS | `go test ./tests/integration/... -count=1` |
|
||||
| Static Analysis | ✅ PASS | `go vet ./...` |
|
||||
| Formatting | ✅ PASS | `gofmt -l .` 空输出 |
|
||||
| Core Coverage | ✅ PASS | `go test -cover ./internal/...`;access 77.3%, pack 72.7%, provision 74.6%(sqlite 61.3% 仅作信息项) |
|
||||
| Core Coverage | ✅ PASS | `go test -cover ./internal/...`;access 80.5%, host/sub2api 78.1%, pack 73.9%, provision 76.3%(sqlite 61.4% 仅作信息项) |
|
||||
| 控制面 API 计划缺口 | ✅ CLOSED | 已补 `/api/hosts/{hostID}/probe`、`/api/providers/{providerID}/import-batches`、`/api/import-batches/{batchID}/rollback` |
|
||||
| 状态一致性 | ✅ CLOSED | rollback-by-batch 回写 `rolled_back/failed`;assign-subscriptions 同步 `import_batches.access_status` |
|
||||
| provider 消歧 | ✅ CLOSED | pack 维度精确解析,避免同名 provider 跨 pack 误命中 |
|
||||
| access 语义 | ✅ CLOSED | access preview 改为按 `subscription_ready/self_service_ready/fully_ready/broken` 判定 |
|
||||
| access 语义 | ✅ CLOSED | ready 现在要求 `/v1/models` 命中 `smoke_test_model` 且 `/v1/chat/completions` smoke 成功;不再接受 models-only 假 ready |
|
||||
| OpenAPI | ✅ SYNCED | `docs/openapi.yaml` 已补当前控制面端点 |
|
||||
| Local runtime smoke | ✅ PASS | `go build ./cmd/{server,cli}`、`GET /healthz`、`GET /api/hosts` |
|
||||
| Local OCI image | ✅ PASS | `docker build -f Dockerfile.local -t sub2api-cn-relay-manager:local .` |
|
||||
| Real-host acceptance tooling | ✅ READY | `docs/REAL_HOST_ACCEPTANCE_RUNBOOK.md` + `scripts/real_host_acceptance.sh` |
|
||||
| Harness regression self-check | ✅ PASS | `bash ./scripts/test_real_host_scripts.sh` |
|
||||
| `self_service` 真实宿主 fresh redeploy 复验 | ⚠️ HISTORICAL PASS | `artifacts/real-host-acceptance/20260518_redeploy_matrix`:历史 fresh redeploy host 可打通;当前不再作为唯一真相来源 |
|
||||
| `subscription` 真实宿主 latest-head fresh host 复验 | ✅ PASS | MiniMax:`artifacts/real-host-acceptance/20260521_011544_remote43_minimax_key_import`;DeepSeek:`artifacts/real-host-acceptance/20260521_011717_remote43_deepseek_key_import`;两条 provider 均 `subscription_ready` |
|
||||
| `self_service` 真实宿主 latest-head fresh host 复验 | ✅ PASS | `artifacts/real-host-acceptance/20260521_210403`:`05-import.json` = `succeeded/self_service_ready/active`,`07-access-status.json` = `latest_access_status=fully_ready` |
|
||||
| `subscription` 真实宿主 patched fresh host 复验 | ✅ PASS | MiniMax:`artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import`;DeepSeek:`artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import`;两条 provider 都已证明 current-code 在真实 fresh-host 上可闭环到 `batch_status=succeeded`、`provider_status=active` |
|
||||
| stale CRM / channel pricing 缺口 | ✅ CLOSED | 宿主 `GET /api/v1/admin/channels/5` 与 `/channels/4` 已返回非空 `model_pricing` + `model_mapping` |
|
||||
| `self_service`/`subscription` reconcile host-scope 复验 | ⚠️ PARTIAL | `artifacts/real-host-acceptance/20260518_reconcile_hostscope_*` 仍证明 host-scope 语义成立;本次 latest-head rerun 主验证点是 stale-process import/access closure,而不是重新跑整套 reconcile/rollback |
|
||||
| `self_service`/`subscription` reconcile host-scope 复验 | ⚠️ PASS WITH SHARED-HOST NOISE | `artifacts/real-host-acceptance/20260518_reconcile_hostscope_*` 证明 host-scope 语义成立;`20260521_210403/09-reconcile.json` 的 `status=drifted` 仅反映共享 fresh-host 历史残留资源,不改变本轮 ready/rollback 结论 |
|
||||
|
||||
## 本轮已关闭项
|
||||
|
||||
@@ -66,13 +73,10 @@
|
||||
- 新增 `docs/REAL_HOST_ACCEPTANCE_RUNBOOK.md`
|
||||
- 新增 `scripts/real_host_acceptance.sh`,把真实宿主验收固化为可落盘 artifact 的流程
|
||||
|
||||
5. 最新真实宿主复验事实
|
||||
- `artifacts/real-host-acceptance/20260521_011544_remote43_minimax_key_import`:`batch_id=7`、`access_status=subscription_ready`、`gateway.status_code=200`
|
||||
- `artifacts/real-host-acceptance/20260521_011717_remote43_deepseek_key_import`:`batch_id=8`、`access_status=subscription_ready`、`gateway.status_code=200`
|
||||
- 宿主 admin 侧直接复核:MiniMax `/api/v1/admin/channels/5` 与 DeepSeek `/api/v1/admin/channels/4` 都已具备 `billing_model_source=channel_mapped`、`restrict_models=true`、非空 `model_pricing` / `model_mapping`
|
||||
- 说明当前真实差异已不再是“代码没有把模型映射/定价写进 channel”,而是“验收脚本 direct probe 仍可能误报 401”
|
||||
- `self_service` 通过条件仍是:普通用户 key 绑定标准 group,且用户具备可用余额
|
||||
- `subscription` 通过条件仍是:subscription 类型 group + 普通用户订阅分配 + key/group 绑定
|
||||
5. 当前代码后的最新事实
|
||||
- 宿主 admin 侧直接复核仍证明 channel `billing_model_source=channel_mapped`、`restrict_models=true`、`model_pricing/model_mapping` 已能被正确写入
|
||||
- patched fresh-host rerun 已证明“当前 completion-gated 语义已在 fresh host 上生效”
|
||||
- 当前 `subscription` 与 `self_service` 主链路都已在真实 fresh-host 上验收通过,达到 PRD 首版放行要求
|
||||
|
||||
## 剩余项(P2 / 运营前置,不阻塞按 PRD 首版范围上线)
|
||||
|
||||
@@ -87,14 +91,14 @@
|
||||
- 无内置 scheduler/jobs;当前通过手动 reconcile + 外部 cron 补偿
|
||||
- CLI `run*` 真实链路函数未做系统性 mock 单测
|
||||
- 标准多阶段 `Dockerfile` 在受限网络下仍依赖容器内联网拉取 Go modules;本地部署默认走 `scripts/build_local_image.sh`
|
||||
- `scripts/import_remote43_provider.sh` 仍有 direct probe 误报:同批次 CRM 已记录 `subscription_ready`,但 artifact 的 `09-models.headers.txt` / `11-chat.headers.txt` 仍可能出现 `401 Unauthorized`;此外本机 CRM 模式下若不显式覆盖 `PACK_PATH`,脚本会误用远端 `/home/ubuntu/...` 路径触发 `stat pack path ... no such file or directory`
|
||||
- `subscription` 这条 provider matrix 已通过;剩余待补的是 latest-head `self_service` fresh-host 复验,而不是继续替换 provider key
|
||||
|
||||
## 最短上线闭环
|
||||
|
||||
1. 按 `docs/REAL_HOST_ACCEPTANCE_RUNBOOK.md` 准备真实宿主普通用户与可复用凭据
|
||||
2. 按目标模式完成 key/group/billing(or subscription) 绑定
|
||||
3. 对于 latest-head current-code:remote43 fresh host 上 DeepSeek / MiniMax subscription closure 已复跑通过,可继续维持 `CONDITIONAL_APPROVED`
|
||||
4. 如需把 tooling 也一并收口,再补修 `scripts/import_remote43_provider.sh` 的 direct probe auth 与本机 `PACK_PATH` 参数化
|
||||
3. 使用当前通过的验收路径复核目标生产宿主
|
||||
4. 对共享 fresh-host 中的历史残留资源做一次环境清理,降低 `reconcile=drifted` 噪音
|
||||
|
||||
## 禁止错误结论
|
||||
|
||||
|
||||
@@ -32,6 +32,12 @@
|
||||
- 真正使用的是 CRM 在宿主侧创建/查找出来的 managed key(`sk-relay-*` 风格)
|
||||
- 因此 subscription 验收如果直接拿调用方原始 probe key 去打 `/v1/models`,出现 `403 not assigned to any group` 并不代表 CRM 主链路失败,而是 probe key 用错了
|
||||
|
||||
4. self_service 场景的 gateway probe 认证语义已经确认
|
||||
- 真实宿主的普通用户 gateway key 访问 `/v1/models` / `/v1/chat/completions` 时,使用的是 `Authorization: Bearer <gateway-key>`
|
||||
- 不能把这条普通用户 gateway key 当成宿主管理 API key 再塞进 `x-api-key`
|
||||
- latest-head 最后一个真实阻断就是这里:CRM 的 `CheckGatewayAccess` / `CheckGatewayCompletion` 之前错误地把 self_service 的普通用户 key 放进了 `x-api-key`
|
||||
- 修复后,latest-head `self_service` 标准 fresh-host 验收 `artifacts/real-host-acceptance/20260521_210403` 已真实收口到 `self_service_ready`
|
||||
|
||||
4. group 聚合视角与 account 单体视角必须分开看
|
||||
- `GET /api/v1/admin/accounts/:id/models` 是 account 单体视角
|
||||
- `GET /v1/models` 是普通用户 key + group 聚合视角
|
||||
@@ -94,6 +100,7 @@
|
||||
经验结论:
|
||||
- 若只做了 key/group 绑定但没余额,`/v1/models` 可能从 403 进入 `INSUFFICIENT_BALANCE`
|
||||
- 这不是 CRM 导入逻辑失败,而是宿主运营前置未完成
|
||||
- 若普通用户 key 直打宿主 `/v1/models` / `/v1/chat/completions` 已经 `200`,但 CRM 的 self_service closure 仍显示 `401/403 broken`,优先检查 CRM 的 gateway probe 是否错误地复用了 `x-api-key` 语义,而不是先怀疑宿主前置
|
||||
|
||||
### subscription
|
||||
|
||||
@@ -158,6 +165,11 @@
|
||||
- 若脚本仍打到旧 relaymgr 宿主,会看到 managed user / key / subscription 状态为空或串台
|
||||
- 需要确保脚本明确指向 fresh host 对应的 `{postgres,redis}` 容器
|
||||
|
||||
7. fresh-host bearer token 过期时,最前面的 host 注册/探测也会伪装成 CRM 侧 502
|
||||
- latest-head `self_service` 收尾时,脚本最前面的 `POST /api/hosts` 曾直接返回 `502`
|
||||
- 继续往里看,upstream detail 才显示 `TOKEN_EXPIRED`
|
||||
- 这类现象不要先误判成 CRM 新代码挂了;应先刷新 fresh-host 管理员 bearer token,再继续验收
|
||||
|
||||
6. 把 `/v1/models` 已通误认为 completion 也一定通
|
||||
- 这不成立
|
||||
- 当前最新真相就是:DeepSeek / MiniMax 的 `/v1/models` 可以 200,但 `/v1/chat/completions` 仍可能因为 host 兼容性或上游 quota 问题失败
|
||||
@@ -213,6 +225,11 @@
|
||||
- 上游 key/quota
|
||||
- 不要先回退归因为 CRM 导入失败
|
||||
|
||||
### 现象 D:普通用户 key 直打宿主 `/v1/models` 与 `/v1/chat/completions` 都是 200,但 CRM 的 `self_service` access/status 仍是 broken
|
||||
优先判断:
|
||||
- CRM 的 gateway probe 是否错误使用了 `x-api-key` 而不是 `Authorization: Bearer`
|
||||
- 当前 online CRM 进程是否真的已经切到包含该修复的新二进制
|
||||
|
||||
### 进一步缩圈:DeepSeek `chat/completions` 当前更像宿主兼容层问题,而不是 key 失效
|
||||
|
||||
2026-05-21 新增的直接证据链:
|
||||
@@ -265,6 +282,8 @@
|
||||
- 目标 Postgres 容器
|
||||
- 目标 Redis 容器
|
||||
|
||||
5. latest-head `self_service` 验收通过后,如果 `reconcile` 仍是 `drifted`,应优先把它解释为 shared fresh-host 的历史残留资源噪音,而不是主链路未打通;判断时先看 `05-import.json` / `07-access-status.json` 的 ready 结果,再看 `09-reconcile.json` 的 `summary.access_status`
|
||||
|
||||
## 凭据与可用性判断矩阵
|
||||
|
||||
先记住:本项目里最容易混淆的不是 API 本身,而是“看起来都像 key,但其实职责完全不同”的几类凭据。
|
||||
|
||||
@@ -196,9 +196,9 @@ artifacts/real-host-acceptance/<timestamp>/
|
||||
## 当前门禁解释
|
||||
|
||||
- 若以上脚本在真实宿主环境全部通过:
|
||||
- 可以把当前项目从 **代码层 `CONDITIONAL_APPROVED`** 推进到 **真实环境放行**
|
||||
- 可以把当前项目推进到 **真实环境放行**
|
||||
- 若脚本未执行:
|
||||
- 仍然只能维持 `CONDITIONAL_APPROVED`
|
||||
- 仍然不能把最新代码直接视作真实宿主已放行
|
||||
- 若脚本执行但失败:
|
||||
- 失败应被归类为真实宿主兼容性 / 凭据 / 网络 / pack 内容问题,而不是再泛化成“代码是否已完成”
|
||||
|
||||
@@ -225,6 +225,10 @@ SKIP_ROLLBACK=1 scripts/real_host_acceptance.sh
|
||||
14. 对“既有 channel 没自动补 `model_pricing`”这类 live 现象,先核对在线 CRM 进程的启动时间与 git 提交时间;之前 MiniMax 的该现象最终被确认是 stale CRM 进程导致,而不是源码缺逻辑。
|
||||
15. 当 CRM 切换到本机运行时,`PACK_PATH` 也必须切换到控制面本机可读路径;继续沿用远端 `/home/ubuntu/...` 会触发 `stat pack path ... no such file or directory`,这是验收 harness 参数问题,不是导入业务逻辑问题。
|
||||
16. 若要把 DeepSeek 的“host `/v1/models`=200 但 host `/v1/chat/completions`=502,而 upstream 直探 `/chat/completions`=200”做成可提 issue 的最小复现,直接运行 `scripts/check_deepseek_completion_split.sh`。它会同时落盘 host `/v1/models`、host `/v1/chat/completions`、upstream `/chat/completions` 三层证据,并在 `summary.json` 里给出 `host_compatibility_gap|upstream_key_quota_issue|unknown` 分类。
|
||||
17. 若 reconcile 面对的是“非 latest batch 的同前缀旧账号”,最新代码会把它们记为 `stale_noise_count` / `stale_noise_accounts` 并保留 `raw_extra_count`,而不是继续把它们算进 `extra_count` 造成 drift 误报;因此应优先看 `extra_count` 是否归零,再看 `probe_failures`/`access_status` 是否仍有真实异常。
|
||||
18. self_service 场景里,普通用户 gateway key 访问宿主 `/v1/models` / `/v1/chat/completions` 时,真实语义是 `Authorization: Bearer <gateway-key>`;若 CRM 的 self_service closure 仍显示 `401/403 broken`,优先排查 gateway probe 是否错误复用了 `x-api-key`。
|
||||
19. fresh-host 管理员 bearer token 过期时,最前面的 `POST /api/hosts` / `probe-host` 可能直接表现成 CRM 侧 `502`。遇到这类现象,先刷新 host bearer token,再继续验收,不要先把它归因为最新代码故障。
|
||||
20. shared fresh-host 上若 `05-import.json` / `07-access-status.json` 已经 ready,而 `09-reconcile.json` 仍是 `status=drifted`,优先把它解释为历史残留资源噪音;PRD 首版放行判断应以 import/access 闭环是否打通为主。
|
||||
|
||||
## 建议固定执行的快速诊断顺序
|
||||
|
||||
|
||||
@@ -5,19 +5,25 @@
|
||||
|
||||
## 当前 Gate 结论
|
||||
|
||||
当前最新 gate:`BLOCKED`
|
||||
当前最新 gate:`APPROVED`
|
||||
|
||||
原因不是基础导入链路仍未打通,而是:
|
||||
1. latest-head fresh host 上,DeepSeek / MiniMax 的 import + access closure 已能进入 `subscription_ready`
|
||||
2. account `credentials.model_mapping`、channel `model_mapping/model_pricing`、managed key 视角 `/v1/models` 都已有 live 证据
|
||||
3. 但 latest completion smoke 仍未完全通过:
|
||||
- DeepSeek:host `/v1/chat/completions` 仍见 `502`,而上游直探 `200`
|
||||
- MiniMax:上游直探为 `403 insufficient_user_quota`
|
||||
4. 因此当前不能宣称 `APPROVED`
|
||||
当前 gate 升到 `APPROVED` 的原因是:
|
||||
1. 代码侧已关闭“只靠 `/v1/models` 就把 access 标成 ready”的假阳性;当前 ready 必须同时通过 `/v1/models` 与 `/v1/chat/completions` smoke
|
||||
2. `scripts/import_remote43_provider.sh` 已补上 upstream `/models` 与 `/chat/completions` 直探,并落盘 `21-summary.json` 做根因分类
|
||||
3. account `credentials.model_mapping`、channel `model_mapping/model_pricing`、managed key 视角 `/v1/models` 都已有 live 证据
|
||||
4. completion-gated 补丁已经在 fresh-host 上重跑验证通过:control plane 会把 completion 失败正确落成 `broken`
|
||||
5. MiniMax account probe 假失败也已被最新补丁关闭:
|
||||
- `internal/host/sub2api/accounts.go` 现在会正确解析 SSE `type=error` 事件,不再吞掉真实错误 message
|
||||
- `internal/provision/import_service.go` 与 reconcile rerun 现在会显式向 `/api/v1/admin/accounts/:id/test` 传 `provider.SmokeTestModel`,不再让宿主默认回退测试 `gpt-5.4`
|
||||
- 最新证据:`artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import/21-summary.json` 已显示 `batch_status=succeeded`、`provider_status=active`
|
||||
6. DeepSeek 2166 与 MiniMax 53hk 两条 `subscription` provider 分支都已完成 latest fresh-host 复验,最新证据分别是 `artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import/21-summary.json` 与 `artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import/21-summary.json`
|
||||
7. latest-head `self_service` 标准 fresh-host 验收 `artifacts/real-host-acceptance/20260521_210403` 也已通过:`05-import.json` = `succeeded/self_service_ready/active`,`07-access-status.json` = `latest_access_status=fully_ready`
|
||||
8. 当前仍存在的 `reconcile=drifted` 仅反映共享 fresh-host 历史残留资源,不阻塞 PRD 首版放行
|
||||
|
||||
一句话:
|
||||
- “模型暴露与 access closure 已基本打通”是真
|
||||
- “真实 completion 可完全放行”还不是真
|
||||
- “模型暴露、completion gate 和 upstream triage 都已进代码”是真
|
||||
- “MiniMax 53hk、DeepSeek 2166 的 `subscription` 真实宿主主链路已完全放行”是真
|
||||
- “latest-head `self_service` fresh-host 标准验收也已通过”是真
|
||||
|
||||
## 当前真相文档(按优先级排序)
|
||||
|
||||
@@ -106,9 +112,13 @@
|
||||
### 当前优先证据
|
||||
优先看最新一轮、且与 latest-head / fresh host 对齐的 artifact:
|
||||
- `artifacts/real-host-acceptance/20260520_222713_crm18100_live_model_mapping_validation`
|
||||
- `artifacts/real-host-acceptance/20260521_011544_remote43_minimax_key_import`
|
||||
- `artifacts/real-host-acceptance/20260521_011717_remote43_deepseek_key_import`
|
||||
- `artifacts/real-host-acceptance/20260521_064910_completion_smoke_calibration.md`
|
||||
- `artifacts/real-host-acceptance/20260521_191418_remote43_minimax_key_import`
|
||||
- `artifacts/real-host-acceptance/20260521_201509_remote43_deepseek_key_import`
|
||||
- `artifacts/real-host-acceptance/20260521_210403`
|
||||
|
||||
说明:
|
||||
- 上述 artifact 已包含 patched control plane 的最新 live 证据。
|
||||
- 它们证明 current-code 的 `subscription` 与 `self_service` 主链路已经在 fresh host 上闭环通过;其中 `20260521_210403` 还补齐了标准 `reconcile/rollback` 验收链路。
|
||||
|
||||
### 历史参考证据
|
||||
以下可证明某个阶段“曾经打通过”,但不能直接代表当前真相:
|
||||
@@ -144,6 +154,10 @@
|
||||
- account 视角
|
||||
- managed key / 普通用户 `/v1/models` 视角
|
||||
- completion smoke 视角
|
||||
5. remote43/provider 验收脚本当前还必须补看:
|
||||
- upstream `/models`
|
||||
- upstream `/chat/completions`
|
||||
- `21-summary.json`
|
||||
|
||||
## 推荐阅读顺序
|
||||
|
||||
|
||||
Reference in New Issue
Block a user