610 lines
32 KiB
Markdown
610 lines
32 KiB
Markdown
> 真源索引:当前文档受 `/home/long/project/立交桥/projects/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md` 纳管。
|
||
> 若阅读顺序、真源优先级或跨文档冲突存在疑问,先看该索引,再回到本基线文档。
|
||
|
||
1. 设计范围:本次覆盖 / 明确不做 / 与 PRD 对应关系
|
||
|
||
1.1 本次覆盖
|
||
- 覆盖模块 A 供应商品质探针,但收敛为“账号健康探测 + 状态写回 + 审计 + gateway 可消费状态快照”。
|
||
- 覆盖模块 B 全网模型发现,但收敛为“已接入供应商的模型列表扫描 + candidate 生成 + 下架告警”,不做广义全网情报平台。
|
||
- 覆盖模块 C 模型准入测试,但收敛为“对 discovered candidate 做标准兼容性验证 + 生成 supply_package 草稿 + 发布闭环”。
|
||
- 模块 E 仅覆盖与主链路直接相关的最小运营干预:手动触发探针、忽略 candidate、确认上架、查看失败原因、查看审计。
|
||
- 覆盖与立交桥主项目的优先集成运行方案。
|
||
- 覆盖对 NewAPI / Sub2API 的最小适配边界:状态读取、模型列表消费、可选发布回调;不反向侵入其内部实现。
|
||
- 覆盖五个 QA 阻塞的显式修复:
|
||
1) 设计范围蔓延
|
||
2) 探针误判规则冲突
|
||
3) candidate 状态机不闭环
|
||
4) 模块关闭一致性缺失
|
||
5) gateway 消费链路未闭环
|
||
|
||
1.2 明确不做
|
||
- 不做独立平台化、多服务拆分、专用 API Gateway、专用消息总线、专用控制台集群。
|
||
- 不做 vector / embedding 检索 / 向量库。
|
||
- 不做 pricing 数据库、模型比价主链路、自动定价、家族回退定价。
|
||
- 不做 predictions / 预测分析 / 广义开放平台 / 社区情报源。
|
||
- 不做 WebSocket 实时推送作为本期前提;工作台可先走普通 HTTP 拉取。
|
||
- 不做 Playwright 浏览器自动化注册主路径;本期仅保留受控自动补给的最小边界:白名单供应商、阈值触发、任务化补给、待验证/待启用,不把浏览器自动化注册链路作为首期上线门槛。
|
||
- 不要求独立 Redis/Temporal/Milvus/Qdrant 等新增重基础设施;优先复用立交桥现有 DB、现有 scheduler、现有审计、现有配置热更新机制。
|
||
- 不自动直接操作 gateway 路由细节表;只提供 package 发布后的内部契约,由 gateway/supply-api 按既有主链路消费。
|
||
|
||
1.3 与 PRD 对应关系
|
||
- AC-01/02/03:保留,落在探针执行、判定、状态迁移、审计与降级策略。
|
||
- AC-04/05:保留,落在扫描、去重、新增 candidate、下架告警。
|
||
- AC-06/07:保留,落在 admission runner、candidate 流转、draft package 生成。
|
||
- AC-08/09:本期不做深自动注册链路,但保留“受控自动补给”的最小产品/技术边界:仅允许白名单供应商、仅允许阈值触发、仅允许生成待补给任务或进入待验证/待启用,不允许把注册浏览器自动化、验证码编排、自动激活作为首期硬门槛。
|
||
- AC-10/11/12:保留,但只保留支撑主链路的最小实现,不扩展成独立大盘平台。
|
||
- PRD 中与商业化、SFI、预测分析、比价报表相关内容不作为本次技术控制面主路径。
|
||
|
||
2. 架构与模块:模块划分、文件/目录落点、关键调用链路、关键依赖与降级边界
|
||
|
||
2.1 总体架构
|
||
基线采用“立交桥主项目内集成模块”模式,而不是独立平台。推荐以 supply-api 内部模块形式落地,原因:
|
||
- 直接复用 supply_accounts / supply_packages / audit / verify / config / scheduler。
|
||
- 避免再造服务间调用、鉴权、部署、监控、迁移复杂度。
|
||
- 更符合立交桥现有 net/http + pgx + PostgreSQL 的简洁架构。
|
||
|
||
独立运行能力保留为简单可选形态:
|
||
- 仅在确有外部项目需要时,封装为同仓内单进程启动入口。
|
||
- 独立运行不得要求新增专用基础设施;仍使用 PostgreSQL + 现有 scheduler 抽象。
|
||
- 不额外设计独立控制台、独立 worker 集群、独立 API 网关。
|
||
|
||
2.2 模块划分
|
||
建议收敛为 6 个模块,均为最小必要:
|
||
|
||
A. probe
|
||
- 读取待探测账号
|
||
- 执行标准探针
|
||
- 依据统一判定规则生成 outcome
|
||
- 驱动 account 状态迁移
|
||
- 写审计与探针日志
|
||
|
||
B. discovery
|
||
- 读取已接入供应商适配器
|
||
- 拉取模型列表
|
||
- 与现有 supply_packages / candidate 去重
|
||
- 创建 candidate
|
||
- 生成模型下架告警待办
|
||
|
||
C. admission
|
||
- 消费 discovered / retry_pending candidate
|
||
- 执行标准测试集
|
||
- 更新 candidate 状态
|
||
- 生成或更新 supply_package draft
|
||
|
||
D. publish
|
||
- 运营确认 package draft
|
||
- 将 package 切到 active
|
||
- 将 candidate 切到 published
|
||
- 写入 gateway 可消费的发布事件/变更记录
|
||
|
||
E. integration
|
||
- 立交桥内部直接集成接口
|
||
- gateway / supply-api 内部契约
|
||
- NewAPI / Sub2API 适配边界
|
||
|
||
F. control
|
||
- 模块开关、停机、运行中任务收敛、配置热更新、幂等、审计
|
||
|
||
2.3 文件/目录落点
|
||
以下为建议落点,优先放入立交桥主项目既有模块内;若 supply-intelligence 仓先行设计,可按同名目录组织:
|
||
- /home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md
|
||
- 建议实现落点参考:
|
||
- supply-api/internal/supplyintelligence/module.go
|
||
- supply-api/internal/supplyintelligence/probe/service.go
|
||
- supply-api/internal/supplyintelligence/probe/evaluator.go
|
||
- supply-api/internal/supplyintelligence/probe/state_machine.go
|
||
- supply-api/internal/supplyintelligence/discovery/service.go
|
||
- supply-api/internal/supplyintelligence/discovery/adapter_registry.go
|
||
- supply-api/internal/supplyintelligence/admission/service.go
|
||
- supply-api/internal/supplyintelligence/admission/runner.go
|
||
- supply-api/internal/supplyintelligence/publish/service.go
|
||
- supply-api/internal/supplyintelligence/integration/http_internal.go
|
||
- supply-api/internal/supplyintelligence/integration/newapi_adapter.go
|
||
- supply-api/internal/supplyintelligence/integration/sub2api_adapter.go
|
||
- supply-api/internal/supplyintelligence/control/shutdown.go
|
||
- supply-api/internal/supplyintelligence/repository/*.go
|
||
- supply-api/sql/*supply_intelligence*.sql
|
||
|
||
2.4 关键调用链路
|
||
|
||
链路 1:探针 -> 状态写回 -> gateway 消费闭环
|
||
1) scheduler 触发 ProbeTick(platform/account batch)
|
||
2) probe.Service.LoadProbeTargets()
|
||
3) probe.Service.RunProbe(accountID)
|
||
4) probe.Evaluator.Classify(response/error) => success / explicit_failure / inconclusive
|
||
5) probe.StateMachine.Apply(account.current_status, recent_probe_window)
|
||
6) repository.UpdateAccountHealthAndStatusTx(...)
|
||
7) repository.AppendAuditLog(...)
|
||
8) repository.UpsertGatewayAccountSnapshot(...)
|
||
9) gateway 通过内部契约读取 snapshot 或随 package/account 查询一起读取可用状态
|
||
|
||
链路 2:扫描 -> candidate -> admission
|
||
1) scheduler 触发 DiscoveryTick(platform)
|
||
2) discovery.Adapter.FetchModels()
|
||
3) discovery.Service.DiffAgainstPackagesAndCandidates()
|
||
4) repository.UpsertModelCandidate(status=discovered)
|
||
5) scheduler enqueue AdmissionRun(candidateID)
|
||
6) admission.Runner.Execute(candidateID)
|
||
7) repository.UpdateCandidateStatus(...)
|
||
8) repository.UpsertDraftPackage(...)
|
||
9) repository.AppendAuditLog(...)
|
||
|
||
链路 3:运营确认上架 -> gateway 消费闭环
|
||
1) ops POST confirm publish
|
||
2) publish.Service.PublishDraft(candidateID, actor)
|
||
3) tx: lock candidate + package draft
|
||
4) package draft -> active
|
||
5) candidate test_passed -> published
|
||
6) append internal event supply_package_published
|
||
7) append audit
|
||
8) gateway/supply-api 既有主链路消费 active package 或发布事件刷新内存路由
|
||
|
||
链路 4:模块关闭闭环
|
||
1) operator/config 将 module.enabled=false
|
||
2) control.ModuleGate.MarkClosing(module)
|
||
3) 新任务拒绝入队/拒绝手动触发
|
||
4) 运行中任务继续到安全提交点或超时中断
|
||
5) 写 module_state=closed when inflight=0
|
||
6) 后续 scheduler tick 直接跳过
|
||
|
||
2.5 关键依赖与降级边界
|
||
- PostgreSQL:强依赖。不可用时所有自动写操作 fail-closed,不做假成功。
|
||
- scheduler:中强依赖。不可用时自动任务暂停,但手动接口可保留。记录告警。
|
||
- supplier adapter:弱依赖。单供应商异常不影响其他供应商。
|
||
- gateway:首期默认事件型消费方。发布链路不等待 gateway 成功回调才提交 package active,但必须通过 package change + ack 保留可追踪消费记录,且必须存在真实消费入口。
|
||
- NewAPI/Sub2API:可选适配依赖。未配置时不影响立交桥内部主链路。
|
||
|
||
降级原则
|
||
- 探针外部错误、429、5xx、DNS/TCP 异常:inconclusive,不推进惩罚性状态迁移。
|
||
- admission 外部超时:candidate 转 retry_pending 或 test_failed,不能生成 active package。
|
||
- gateway 消费延迟:package 可 active,但需要“未消费/待同步”状态位和审计,不可假定已生效。
|
||
- 模块关闭中:新任务一律拒绝,运行中任务只允许安全收尾。
|
||
|
||
3. 接口与数据模型:API/RPC/事件、数据模型/schema、错误码、安全/鉴权契约
|
||
|
||
3.1 接口分类
|
||
|
||
3.1.1 立交桥内部直接集成接口
|
||
用途:供立交桥主项目内其他模块直接调用,优先 Go 接口,不先暴露额外网络跳。
|
||
|
||
interface SupplyIntelligenceModule {
|
||
RunProbe(ctx context.Context, accountID int64, trigger string) (*ProbeOutcome, error)
|
||
ScanPlatform(ctx context.Context, platform string, trigger string) (*ScanOutcome, error)
|
||
RunAdmission(ctx context.Context, candidateID int64, trigger string) (*AdmissionOutcome, error)
|
||
PublishCandidate(ctx context.Context, candidateID int64, actor string) (*PublishOutcome, error)
|
||
GetAccountRoutingState(ctx context.Context, accountID int64) (*AccountRoutingState, error)
|
||
}
|
||
|
||
3.1.2 给 gateway / supply-api 使用的内部契约
|
||
用途:形成真实消费闭环,避免“文档说 gateway 会用,但无真实契约”。
|
||
|
||
HTTP internal 契约,前缀建议:/internal/supply-intelligence
|
||
|
||
1) GET /internal/supply-intelligence/accounts/{account_id}/routing-state
|
||
响应:
|
||
{
|
||
"account_id": 123,
|
||
"platform": "openai",
|
||
"account_status": "active",
|
||
"routing_enabled": true,
|
||
"risk_score": 20,
|
||
"reason_code": "ok",
|
||
"last_probe_at": "2026-05-06T15:00:00Z",
|
||
"version": 17
|
||
}
|
||
|
||
2) GET /internal/supply-intelligence/models/{platform}/{model}/admission-state
|
||
响应:
|
||
{
|
||
"platform": "openai",
|
||
"model": "gpt-4.1-mini",
|
||
"candidate_status": "published",
|
||
"package_id": 456,
|
||
"package_status": "active",
|
||
"gateway_sync_status": "pending|applied|failed|not_required",
|
||
"version": 9
|
||
}
|
||
|
||
3) GET /internal/supply-intelligence/gateway/package-changes?cursor=...
|
||
响应:
|
||
{
|
||
"items": [
|
||
{
|
||
"event_id": "evt_001",
|
||
"event_type": "supply_package_published",
|
||
"package_id": 456,
|
||
"platform": "openai",
|
||
"model": "gpt-4.1-mini",
|
||
"occurred_at": "2026-05-06T15:00:00Z",
|
||
"version": 9
|
||
}
|
||
],
|
||
"next_cursor": "..."
|
||
}
|
||
|
||
4) POST /internal/supply-intelligence/gateway/package-changes/{event_id}/ack
|
||
请求:
|
||
{
|
||
"consumer": "gateway",
|
||
"result": "applied|failed",
|
||
"detail": "optional"
|
||
}
|
||
响应:204
|
||
|
||
闭环定义
|
||
- 发布成功 != gateway 已消费。
|
||
- 只有 gateway ack event_id 后,gateway_sync_status 才能从 pending -> applied/failed。
|
||
- QA 必须验证 publish -> list changes -> ack 的真实链路。
|
||
|
||
3.1.3 面向 NewAPI/Sub2API 的适配边界
|
||
原则:只暴露最小必要只读/回调能力,不把本系统设计成它们的管理平台。
|
||
|
||
适配边界 A:状态拉取
|
||
- GET /adapter/v1/supply-status/accounts/{account_id}
|
||
- 字段与 routing-state 对齐,但去掉内部实现细节。
|
||
|
||
适配边界 B:模型拉取
|
||
- GET /adapter/v1/models?status=published
|
||
响应只返回已 published 且 package active 的模型。
|
||
|
||
适配边界 C:可选发布回调下发
|
||
- POST /adapter/v1/package-events
|
||
仅在对方需要 webhook 模式时启用;默认不要求。
|
||
|
||
适配边界约束
|
||
- 不暴露审计明细。
|
||
- 不暴露原始探针日志。
|
||
- 不暴露账号凭证、测试账号信息、内部风险算法细节。
|
||
- 仅允许配置白名单来源访问。
|
||
|
||
3.2 数据模型/schema
|
||
|
||
3.2.1 probe_execution_logs
|
||
- id bigint pk
|
||
- account_id bigint not null
|
||
- platform varchar(64) not null
|
||
- probe_result varchar(32) not null 取值: success | explicit_failure | inconclusive
|
||
- failure_class varchar(64) null 取值: auth_invalid | quota_empty | timeout | tcp_error | dns_error | rate_limited | upstream_5xx | parse_error
|
||
- http_status int null
|
||
- latency_ms int null
|
||
- risk_score int not null
|
||
- evaluated_transition varchar(64) not null 取值: no_change | active_to_suspended | suspended_to_disabled | suspended_to_active
|
||
- executed_at timestamptz not null
|
||
- request_id varchar(64) not null
|
||
- index(account_id, executed_at desc)
|
||
|
||
3.2.2 model_candidates
|
||
- id bigint pk
|
||
- platform varchar(64) not null
|
||
- model varchar(128) not null
|
||
- status varchar(32) not null
|
||
- discovery_source varchar(32) not null 取值: official_api | official_doc | manual_seed
|
||
- last_scan_at timestamptz not null
|
||
- discovered_at timestamptz not null
|
||
- last_test_at timestamptz null
|
||
- failure_reason_code varchar(64) null
|
||
- failure_summary text null
|
||
- ignored_until timestamptz null
|
||
- package_id bigint null
|
||
- version int not null default 1
|
||
- unique(platform, model)
|
||
|
||
candidate 最终闭环状态机
|
||
- discovered:扫描新发现,可入测试
|
||
- testing:测试执行中
|
||
- test_passed:测试通过,已存在 draft package
|
||
- test_failed:测试失败,允许人工重试或自动进入 retry_pending
|
||
- retry_pending:等待下次重试
|
||
- ignored:运营临时忽略,到 ignored_until 后自动回 discovered
|
||
- published:运营已确认上架,package active
|
||
- deprecated:供应商侧已消失,已产生运营待办,但历史保留
|
||
- closed:不再处理的终态,仅用于模型被明确弃用/手工关闭
|
||
|
||
合法迁移
|
||
- discovered -> testing
|
||
- testing -> test_passed | test_failed | retry_pending
|
||
- test_failed -> retry_pending | closed
|
||
- retry_pending -> testing | closed
|
||
- discovered | test_failed | retry_pending -> ignored
|
||
- ignored -> discovered
|
||
- test_passed -> published | closed
|
||
- published -> deprecated | closed
|
||
- deprecated -> closed
|
||
|
||
闭环修复点
|
||
- 任何非终态都存在后继处理路径。
|
||
- ignored 有自动回流。
|
||
- published/deprecated 最终可归档到 closed。
|
||
- 不再存在“只定义中间态、无出口”的 QA 阻塞。
|
||
|
||
3.2.3 gateway_package_events
|
||
- event_id varchar(64) pk
|
||
- event_type varchar(64) not null
|
||
- package_id bigint not null
|
||
- candidate_id bigint null
|
||
- payload jsonb not null
|
||
- consumer varchar(64) null
|
||
- consumer_status varchar(32) not null default 'pending'
|
||
- consumer_detail text null
|
||
- occurred_at timestamptz not null
|
||
- acked_at timestamptz null
|
||
- retry_count int not null default 0
|
||
|
||
3.2.4 module_runtime_state
|
||
- module_name varchar(64) pk
|
||
- desired_state varchar(16) not null 取值: enabled | disabled
|
||
- runtime_state varchar(16) not null 取值: starting | running | closing | closed
|
||
- inflight_count int not null
|
||
- updated_at timestamptz not null
|
||
|
||
3.3 探针判定统一规则
|
||
这是本轮必须修的 QA 阻塞之一,统一如下:
|
||
|
||
明确失败 explicit_failure
|
||
- HTTP 401/403
|
||
- 供应商明确返回 key invalid / account suspended / quota exhausted 且可稳定识别
|
||
|
||
不可判定 inconclusive
|
||
- HTTP 429
|
||
- HTTP 5xx
|
||
- DNS 失败
|
||
- TCP 连接失败
|
||
- 超时
|
||
- 响应体为空或格式突变
|
||
|
||
成功 success
|
||
- 返回 2xx 且最小校验通过
|
||
|
||
状态迁移规则
|
||
- active + 1 次 explicit_failure -> suspended
|
||
- suspended + 最近连续 3 次 explicit_failure -> disabled
|
||
- suspended + 1 次 success -> active
|
||
- disabled 不自动恢复,只能人工恢复到 active 或 closed
|
||
- inconclusive 永不计入 explicit failure 连续次数
|
||
|
||
说明
|
||
- 将 timeout/TCP/DNS 从“失败导致降级”统一修正为 inconclusive,消除 PRD/HLD 冲突。
|
||
- 若未来某供应商能明确证明 timeout 即余额停用,也必须走供应商级覆盖配置,不改全局默认。
|
||
|
||
3.4 错误码
|
||
- SUP_INT_PROBE_NOT_FOUND 404
|
||
- SUP_INT_PROBE_MODULE_DISABLED 409
|
||
- SUP_INT_CANDIDATE_NOT_FOUND 404
|
||
- SUP_INT_CANDIDATE_STATE_INVALID 409
|
||
- SUP_INT_PUBLISH_PACKAGE_MISSING 409
|
||
- SUP_INT_GATEWAY_ACK_CONFLICT 409
|
||
- SUP_INT_ADAPTER_UNSUPPORTED 400
|
||
- SUP_INT_AUTH_FORBIDDEN 403
|
||
- SUP_INT_CONFIG_INVALID 400
|
||
- SUP_INT_UPSTREAM_TEMPORARY 503
|
||
|
||
3.5 安全/鉴权契约
|
||
- 内部接口只允许立交桥内部服务身份访问,走现有 internal auth middleware。
|
||
- NewAPI/Sub2API 适配接口必须使用独立 access key 或签名校验,按来源白名单限制。
|
||
- 审计字段必须包含 object_type/object_id/action/result_code/before_state/after_state/request_id/actor。
|
||
- 任何日志不得输出明文 API key、cookie、token、测试账号凭证。
|
||
- 手动发布、手动恢复 disabled 账号、关闭 candidate 必须要求 operator 身份并审计。
|
||
|
||
4. 任务拆解:每个任务必须有具体文件路径和函数名,粒度 2-5 分钟
|
||
|
||
说明:以下为 Engineer 最小实现任务单,按设计拆到文件级与函数级。路径以优先集成到 supply-api 为准。
|
||
|
||
4.1 模块骨架
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/module.go :: func RegisterModule(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/module.go :: func MountInternalRoutes(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/module.go :: func RegisterSchedulers(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/control/shutdown.go :: func BeginModuleClose(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/control/shutdown.go :: func FinishInflightTask(...) error
|
||
|
||
4.2 probe
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/service.go :: func LoadProbeTargets(ctx context.Context, limit int) ([]Account, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/service.go :: func RunProbe(ctx context.Context, accountID int64, trigger string) (*ProbeOutcome, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/evaluator.go :: func ClassifyProbeResult(resp *http.Response, err error) ProbeClass
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/evaluator.go :: func CalculateRiskScore(class ProbeClass) int
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/state_machine.go :: func ApplyAccountTransition(current string, recent []ProbeClass) (next string, transition string)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/state_machine.go :: func CountRecentExplicitFailures(recent []ProbeClass) int
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/worker.go :: func HandleProbeTick(ctx context.Context) error
|
||
|
||
4.3 discovery
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/adapter_registry.go :: func ResolveModelAdapter(platform string) (ModelAdapter, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/service.go :: func ScanPlatform(ctx context.Context, platform string, trigger string) (*ScanOutcome, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/service.go :: func DiffModels(current []string, packages []string, candidates []string) DiffResult
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/service.go :: func UpsertDiscoveredCandidates(ctx context.Context, platform string, models []string) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/service.go :: func MarkDeprecatedAlerts(ctx context.Context, platform string, missing []string) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/discovery/worker.go :: func HandleDiscoveryTick(ctx context.Context) error
|
||
|
||
4.4 admission
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/service.go :: func EnqueueAdmission(ctx context.Context, candidateID int64) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/service.go :: func RunAdmission(ctx context.Context, candidateID int64, trigger string) (*AdmissionOutcome, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/runner.go :: func LoadCandidateForTesting(ctx context.Context, candidateID int64) (*Candidate, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/runner.go :: func ExecuteTestSuite(ctx context.Context, c *Candidate) (*SuiteResult, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/runner.go :: func DecideCandidateNextState(result *SuiteResult) (string, string)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/runner.go :: func UpsertDraftPackage(ctx context.Context, c *Candidate, result *SuiteResult) (int64, error)
|
||
|
||
4.5 publish
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/publish/service.go :: func PublishCandidate(ctx context.Context, candidateID int64, actor string) (*PublishOutcome, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/publish/service.go :: func ValidatePublishable(ctx context.Context, candidateID int64) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/publish/service.go :: func AppendGatewayPackageEvent(ctx context.Context, packageID int64, candidateID int64) error
|
||
|
||
4.6 integration
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal.go :: func GetAccountRoutingState(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal.go :: func GetModelAdmissionState(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal.go :: func ListGatewayPackageChanges(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal.go :: func AckGatewayPackageChange(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/newapi_adapter.go :: func ListPublishedModels(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/newapi_adapter.go :: func GetExternalAccountStatus(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/sub2api_adapter.go :: func ListPublishedModels(w http.ResponseWriter, r *http.Request)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/sub2api_adapter.go :: func GetExternalAccountStatus(w http.ResponseWriter, r *http.Request)
|
||
|
||
4.7 repository / sql
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/probe_repo.go :: func InsertProbeExecutionLog(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/probe_repo.go :: func UpdateAccountHealthAndStatusTx(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/candidate_repo.go :: func UpsertModelCandidate(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/candidate_repo.go :: func UpdateCandidateStateTx(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/package_repo.go :: func UpsertDraftPackageTx(...) (int64, error)
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/gateway_repo.go :: func InsertGatewayPackageEventTx(...) error
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/gateway_repo.go :: func AckGatewayPackageEventTx(...) error
|
||
- /home/long/project/立交桥/supply-api/sql/xxxx_supply_intelligence_probe_logs.sql :: migration create table
|
||
- /home/long/project/立交桥/supply-api/sql/xxxx_supply_intelligence_candidates.sql :: migration create table
|
||
- /home/long/project/立交桥/supply-api/sql/xxxx_supply_intelligence_gateway_events.sql :: migration create table
|
||
- /home/long/project/立交桥/supply-api/sql/xxxx_supply_intelligence_module_runtime.sql :: migration create table
|
||
|
||
4.8 测试与校验
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/state_machine_test.go :: func TestApplyAccountTransition()
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/probe/evaluator_test.go :: func TestClassifyProbeResult()
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/admission/runner_test.go :: func TestDecideCandidateNextState()
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/publish/service_test.go :: func TestPublishCandidate_AppendsGatewayEvent()
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal_test.go :: func TestGatewayEventAckFlow()
|
||
|
||
5. 风险与保护:风险清单(概率/影响/缓解)、降级策略、威胁建模结果
|
||
|
||
5.1 风险清单
|
||
1) 探针误判导致错误下线
|
||
- 概率:中
|
||
- 影响:高
|
||
- 缓解:只允许 explicit_failure 触发惩罚状态;429/超时/网络错误全部 inconclusive;disabled 仅连续 3 次明确失败;生产初期可只告警不自动 disabled。
|
||
|
||
2) candidate 重复创建或状态乱序
|
||
- 概率:中
|
||
- 影响:中
|
||
- 缓解:unique(platform, model);version 乐观锁;状态迁移函数集中校验;测试任务拿行锁。
|
||
|
||
3) gateway 未真实消费已上架 package
|
||
- 概率:高
|
||
- 影响:高
|
||
- 缓解:新增 gateway_package_events + ack 契约;区分 published 与 gateway applied;监控 pending backlog。
|
||
|
||
4) 模块关闭时仍有脏写入
|
||
- 概率:中
|
||
- 影响:中
|
||
- 缓解:runtime_state=closing 时拒绝新任务;inflight 计数;安全提交点;超时取消 ctx。
|
||
|
||
5) 适配器变更影响扫描质量
|
||
- 概率:中
|
||
- 影响:中
|
||
- 缓解:按供应商隔离;单平台失败不扩散;保留 last_successful_scan 基线;失败仅告警不删数据。
|
||
|
||
6) NewAPI/Sub2API 适配越权暴露内部数据
|
||
- 概率:低
|
||
- 影响:高
|
||
- 缓解:适配接口单独 DTO;白名单认证;不复用内部 debug 输出。
|
||
|
||
5.2 降级策略
|
||
- probe 模块关闭:gateway 继续依赖现有 account/package 状态;新鲜度下降但主链路可运行。
|
||
- discovery 模块关闭:不再发现新模型;已上架模型不受影响。
|
||
- admission 模块关闭:candidate 可积压,但不会误上架。
|
||
- publish 后 gateway 未消费:保留 pending,运营可见;不回滚 package active,但不得宣称“已进路由”。
|
||
- NewAPI/Sub2API 未配置:直接关闭适配路由,不影响内部主链路。
|
||
|
||
5.3 威胁建模结果
|
||
输入边界
|
||
- 供应商返回体属于不可信输入:必须限长、schema 校验、错误脱敏。
|
||
- 运营手动接口属于高权限输入:必须鉴权、审计、幂等。
|
||
- gateway ack 请求属于内部写接口:必须鉴权并校验 event_id/consumer 一致性。
|
||
|
||
数据流
|
||
- supplier -> adapter -> evaluator -> db
|
||
- db -> internal route -> gateway
|
||
- db -> adapter route -> NewAPI/Sub2API
|
||
|
||
主要威胁与处置
|
||
- 凭证泄漏:本期不纳入自动注册主路径;现有账号密钥仅走既有安全存储,不在本模块新增明文链路。
|
||
- 重放/重复发布:publish 接口需幂等,published candidate 再次 publish 返回 409。
|
||
- 伪造 gateway ack:只接受内部服务身份;event consumer 固定枚举。
|
||
- 大响应体压垮解析:adapter 限制 body size,超限视为 inconclusive/scan_failed。
|
||
- SQL 并发覆盖:关键状态表使用 version 或 select for update。
|
||
|
||
6. QA 交接与实施约束:编码前设计审查要点、编码后漂移检查点、必查真实调用链路、禁止偏离的边界
|
||
|
||
6.1 编码前设计审查要点
|
||
- 是否明确“集成运行优先,独立运行可选且轻量”。
|
||
- 是否删除 pricing/vector/predictions/开放平台化内容。
|
||
- 探针默认规则是否统一为 explicit_failure 才触发状态惩罚。
|
||
- candidate 状态机是否存在完整入口、出口、终态与回流。
|
||
- gateway 是否存在 list change + ack 的真实闭环,而非只有查询接口。
|
||
- 模块关闭是否存在 closing -> closed 收敛语义。
|
||
- NewAPI/Sub2API 是否仅作为适配边界,而非反向牵引主架构。
|
||
|
||
6.2 编码后漂移检查点
|
||
- 是否出现新增 Redis/Temporal/Kafka/MQ/向量库等重基础设施前置依赖。
|
||
- 是否出现额外独立服务、额外 API gateway、复杂事件总线。
|
||
- 是否把自动注册重新抬回本期主路径。
|
||
- 是否把 gateway 路由刷新实现成跨系统强耦合同步 RPC 必须成功。
|
||
- 是否新增未在本基线定义的中间状态。
|
||
- 是否把 timeout/TCP/DNS 再次当成 explicit_failure。
|
||
|
||
6.3 QA 必查真实调用链路
|
||
- probe tick -> evaluator -> state machine -> supply_accounts 写回 -> audit 写入
|
||
- discovery tick -> candidate discovered -> admission run -> draft package
|
||
- publish confirm -> package active -> candidate published -> gateway change event -> gateway ack
|
||
- module disable -> closing -> reject new task -> inflight drain -> closed
|
||
- adapter route -> NewAPI/Sub2API 只读返回,字段不泄露内部敏感信息
|
||
|
||
6.4 禁止偏离的边界
|
||
- 禁止把本期做成独立平台化部署前提。
|
||
- 禁止把比价、预测、向量检索恢复为主链路。
|
||
- 禁止未定义契约就声称“gateway 会消费”。
|
||
- 禁止 candidate 状态直接跳 published,绕过 test_passed + draft package。
|
||
- 禁止 disabled 自动恢复。
|
||
- 禁止模块关闭时直接 kill 运行中事务而无收敛策略。
|
||
|
||
7. Engineer 实施说明:文件级落点、最小验证项、需 PM 澄清项
|
||
|
||
7.1 文件级落点
|
||
优先实施目录:
|
||
- /home/long/project/立交桥/supply-api/internal/supplyintelligence/
|
||
- /home/long/project/立交桥/supply-api/sql/
|
||
- /home/long/project/立交桥/supply-api/internal/http/internal/
|
||
|
||
若 supply-intelligence 项目仓仅承载设计文档,则本文件作为交付基线,后续代码并入 supply-api 主仓。
|
||
|
||
7.2 最小验证项
|
||
- 单测:探针分类、账号状态迁移、candidate 状态迁移、publish 幂等。
|
||
- 集成测:publish 后产生 gateway event,gateway ack 后状态更新 applied。
|
||
- 集成测:module closing 时手动触发探针返回 409 module disabled/closing。
|
||
- E2E 最小链路:
|
||
1) 一个 active 账号 401 -> suspended
|
||
2) 一个新模型 discovered -> test_passed -> draft -> published
|
||
3) gateway 拉取 package change 并 ack
|
||
|
||
7.3 需 PM 澄清项
|
||
- 本期是否允许 production 初期仅启用 active->suspended,暂不自动 disabled。
|
||
- candidate ignored 的默认恢复期是否固定 7 天,或允许按供应商配置。
|
||
- gateway 首期默认采用 pull package-changes + ack 作为事件型消费闭环;若后续证明已有内部刷新入口可复用,也必须保留等价 ack 语义与可审计消费状态。
|
||
- NewAPI/Sub2API 本期需要只读拉取,还是还需要 webhook 模式;默认只做只读拉取。
|
||
|
||
8. 阶段门控结论:可进入 QA 设计审查 / 需返回 PM / 需继续补设计
|
||
|
||
结论:可进入 QA 设计审查
|
||
|
||
理由
|
||
- 五个 QA 阻塞已在本基线中逐项补洞并收敛。
|
||
- 架构已回到立交桥一致的简洁集成模式。
|
||
- 对立交桥 / NewAPI / Sub2API 的边界已最小化并显式分类。
|
||
- 已删除明显超范围和重基础设施设计。
|
||
|
||
附带条件
|
||
- 不代表可直接开发放行。
|
||
- 进入开发前仍需确认 PM 澄清项中的 gateway 消费方式与 production 初期自动 disabled 策略。
|
||
|
||
9. 下游执行约束摘要:
|
||
- Engineer 禁止偏离:不得新增独立平台化部署前提、不得恢复 pricing/vector/predictions 主路径、不得绕过 gateway event ack 闭环、不得新增未定义 candidate 状态。
|
||
- QA 必查调用链路:probe->状态写回;discovery->candidate->admission->draft;publish->gateway event->ack;module disable->closing->drain->closed;NewAPI/Sub2API 只读适配边界。
|
||
- XL 若继续推进需补的门控:确认 gateway 实际消费方式;确认生产首期自动 disabled 策略;确认代码最终并入 supply-api 主仓而非另起独立重部署。
|
||
|
||
自检清单
|
||
- [x] 架构设计覆盖 PRD 所有 AC
|
||
- [x] 接口定义完整(请求/响应/错误)
|
||
- [x] 每个任务 < 5分钟,有明确文件路径
|
||
- [x] 依赖关系无循环
|
||
- [x] 考虑了扩展点(未来可能的变化)
|
||
- [x] 风险评估完整,有关键风险的缓解方案
|
||
- [x] 符合项目现有技术栈和编码规范
|
||
- [x] 降级策略已设计(熔断/限流/兜底)
|
||
- [x] 威胁建模已完成(输入边界/鉴权/数据流)
|
||
- [x] 实施漂移检测点已定义(可与 QA checklist 对接)
|
||
- [x] 已明确标记是否可进入 QA 设计审查
|
||
- [x] 已提供 QA 编码前审查与编码后漂移检测所需交接物
|
||
- [x] 已给出 Engineer / QA / XL 的下游执行约束摘要
|
||
- [x] 已纳入立交桥简洁架构与立交桥/NewAPI/Sub2API 集成边界
|