feat: bootstrap supply intelligence baseline
This commit is contained in:
609
tech/BASELINE_TECHLEAD_V2.md
Normal file
609
tech/BASELINE_TECHLEAD_V2.md
Normal file
@@ -0,0 +1,609 @@
|
||||
> 真源索引:当前文档受 `/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 集成边界
|
||||
118
tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md
Normal file
118
tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# Supply-Intelligence 当前实现真源索引(2026-05)
|
||||
|
||||
> 状态:当前有效
|
||||
> 目的:为 Engineer / QA / PM 提供单一阅读入口,避免继续误读历史草案。
|
||||
> 适用范围:/home/long/project/立交桥/projects/supply-intelligence/
|
||||
|
||||
## 1. 当前结论
|
||||
|
||||
当前规划包已收敛到“可进入 Engineer 实现”状态。
|
||||
当前总门控结论:APPROVED。
|
||||
|
||||
但 APPROVED 的前提是:实现、测试、评审都必须以本文件列出的“当前真源”解释,不得回退到旧 PRD/HLD/INTERFACE/DEPLOYMENT 的正文口径。
|
||||
|
||||
## 2. 当前真源文件(按优先级)
|
||||
|
||||
### 2.1 一级真源:必须优先遵循
|
||||
1. `/home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md`
|
||||
- 作用:当前技术基线、状态机、模块边界、集成约束、最小生产闭环定义
|
||||
- 适用问题:实现边界、状态迁移、部署形态、首期能力范围、风险与验证要求
|
||||
|
||||
2. `/home/long/project/立交桥/projects/supply-intelligence/tech/GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
- 作用:首期 package/account 消费闭环决议
|
||||
- 适用问题:published vs applied、gateway 是否默认消费方、package change + ack、真实调用链落点
|
||||
|
||||
### 2.2 二级真源:必须按一级真源解释
|
||||
3. `/home/long/project/立交桥/projects/supply-intelligence/tech/TEST_DESIGN.md`
|
||||
- 作用:收敛后的测试门禁文档
|
||||
- 使用规则:
|
||||
- 只能按一级真源解释
|
||||
- 当前阶段门控结论以其中已更新的 APPROVED 段落为准
|
||||
- 若正文某处仍残留旧测试假设,以一级真源覆盖
|
||||
|
||||
4. `/home/long/project/立交桥/projects/supply-intelligence/specs/功能清单.md`
|
||||
- 作用:任务粒度参考清单
|
||||
- 使用规则:
|
||||
- 仅用于任务拆分、实现排程、UI/后端任务定位
|
||||
- 若与一级真源冲突,一律以一级真源为准
|
||||
- 不得把其中任何历史平台化/重基础设施/深自动注册项当作默认首期门槛
|
||||
|
||||
## 3. 历史参考文件(禁止作为当前实现真源)
|
||||
|
||||
以下文件只能用于理解历史上下文,不能再作为 Engineer/QA 的当前实现依据:
|
||||
|
||||
1. `/home/long/project/立交桥/projects/supply-intelligence/prd/PRD.md`
|
||||
2. `/home/long/project/立交桥/projects/supply-intelligence/tech/HLD.md`
|
||||
3. `/home/long/project/立交桥/projects/supply-intelligence/tech/INTERFACE.md`
|
||||
4. `/home/long/project/立交桥/projects/supply-intelligence/tech/DEPLOYMENT.md`
|
||||
|
||||
原因:这些文件虽已加失效声明,但正文仍保留大量旧设计,例如:
|
||||
- pricing / prediction / 向量检索 / 仪表盘扩张
|
||||
- 独立 API/worker/重基础设施默认前提
|
||||
- gateway 管理接口热更新主路径
|
||||
- 深自动注册 / 浏览器自动化主路径
|
||||
- published 与 gateway applied 语义混淆
|
||||
|
||||
## 4. Engineer 必须先建立的统一理解
|
||||
|
||||
### 4.1 首期能力边界
|
||||
首期目标不是独立平台化大系统,而是“立交桥延伸项目 + 简洁集成架构 + 最小生产闭环”。
|
||||
|
||||
这意味着:
|
||||
- 优先并入 supply-api 主仓
|
||||
- 优先复用主仓已有配置、调度、审计、内部路由能力
|
||||
- 不把 Redis / Temporal / 向量数据库 / WebSocket / MQ 作为首期硬前置
|
||||
- 不做 pricing / prediction / recommendation / SFI 仪表盘扩张
|
||||
|
||||
### 4.2 探针判定边界
|
||||
必须按 explicit_failure / inconclusive / success 三类解释,不能回退到旧的“timeout 直接惩罚性降级”口径。
|
||||
|
||||
### 4.3 自动补给边界
|
||||
首期不是深自动注册主路径。
|
||||
首期仅保留“受控自动补给最小边界”:
|
||||
- 白名单供应商
|
||||
- 阈值触发
|
||||
- 任务化补给或受控补给受理接口
|
||||
- pending_verify / pending_enable 等受控中间态
|
||||
- fail-closed
|
||||
|
||||
不得默认实现:
|
||||
- 浏览器自动化注册
|
||||
- 短信验证码编排主路径
|
||||
- 无审批直接自动激活
|
||||
|
||||
### 4.4 gateway 消费闭环边界
|
||||
首期默认采用:
|
||||
- package 发布链路:event + ack
|
||||
- account 状态链路:查询型消费
|
||||
|
||||
必须明确:
|
||||
- published != applied
|
||||
- active package != gateway 已消费成功
|
||||
- 没有真实 poll/apply/ack 入口,不得宣称 package 发布链路已完成
|
||||
|
||||
## 5. QA 审查必须卡的四条红线
|
||||
|
||||
1. 若实现重新引入 published/applied 混淆,直接打回
|
||||
2. 若把深自动注册重新膨胀成首期硬门槛,直接打回
|
||||
3. 若把旧独立平台化基础设施重新作为首期依赖,直接打回
|
||||
4. 若 gateway 只有接口定义、没有真实消费方入口与 ack 回写,直接打回
|
||||
|
||||
## 6. 推荐阅读顺序
|
||||
|
||||
Engineer / QA / PM 开始工作前,按以下顺序阅读:
|
||||
1. `tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md`
|
||||
2. `tech/BASELINE_TECHLEAD_V2.md`
|
||||
3. `tech/GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
4. `tech/TEST_DESIGN.md`
|
||||
5. `specs/功能清单.md`
|
||||
|
||||
禁止跳过前 3 份文件直接依据旧 PRD/HLD/INTERFACE/DEPLOYMENT 开始实现。
|
||||
|
||||
## 7. 一句话执行规则
|
||||
|
||||
如果某个设计点在文档间出现冲突:
|
||||
- 先看 `BASELINE_TECHLEAD_V2.md`
|
||||
- 再看 `GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
- 然后用 `TEST_DESIGN.md` 和 `功能清单.md` 做验证与任务拆解
|
||||
- 不回退到旧草案正文做判断
|
||||
168
tech/DEPLOYMENT.md
Normal file
168
tech/DEPLOYMENT.md
Normal file
@@ -0,0 +1,168 @@
|
||||
# Supply-Intelligence 部署设计
|
||||
|
||||
> 状态说明(2026-05 收敛修订):本文件保留为旧版部署草案,已不再作为当前默认部署真源。
|
||||
> 当前默认部署真源应以“立交桥延伸项目 + 简洁集成架构”为准:优先并入 supply-api 主仓,独立运行仅为轻量可选形态。
|
||||
> 以下旧部署假设已废止,不得再作为首期落地前提:
|
||||
> - 独立 API Server + 多 Worker 集群默认部署
|
||||
> - Redis / 向量数据库 / WebSocket / 独立共享层作为首期前置依赖
|
||||
> - 以独立多组件容器拓扑替代主仓集成部署
|
||||
|
||||
> 版本:v1.0 | 状态:初稿
|
||||
|
||||
---
|
||||
|
||||
## 1. 部署架构
|
||||
|
||||
### 1.1 总体架构
|
||||
|
||||
```
|
||||
├── Load Balancer (Nginx / 云 CLB)
|
||||
│
|
||||
├── Supply-Intelligence API Server x 2
|
||||
│ │
|
||||
│ ├── HTTP API
|
||||
│ └── WebSocket (健康大盘实时推送)
|
||||
│
|
||||
├── Supply-Intelligence Worker x 3
|
||||
│ │
|
||||
│ ├── Probe Worker (探针任务)
|
||||
│ ├── Discovery Worker (扫描任务)
|
||||
│ ├── Admission Worker (准入测试任务)
|
||||
│ ├── Auto-Reg Worker (自动注册任务)
|
||||
│ └── Cleanup Worker (定期清理)
|
||||
│
|
||||
└── 共享层
|
||||
│
|
||||
├── PostgreSQL 15+ (与 supply-api 共存或独立)
|
||||
├── Redis (缓存 + 锁 + 扫描结果缓存)
|
||||
└── 向量数据库 (PGVector / Milvus / Qdrant)
|
||||
```
|
||||
|
||||
### 1.2 容器化部署
|
||||
|
||||
```yaml
|
||||
services:
|
||||
supply-intel-api:
|
||||
image: supply-intelligence:latest
|
||||
command: ["./supply-intel", "api"]
|
||||
replicas: 2
|
||||
ports:
|
||||
- "8081:8080"
|
||||
|
||||
supply-intel-probe:
|
||||
image: supply-intelligence:latest
|
||||
command: ["./supply-intel", "worker", "probe"]
|
||||
replicas: 1
|
||||
|
||||
supply-intel-discovery:
|
||||
image: supply-intelligence:latest
|
||||
command: ["./supply-intel", "worker", "discovery"]
|
||||
replicas: 1
|
||||
|
||||
supply-intel-admission:
|
||||
image: supply-intelligence:latest
|
||||
command: ["./supply-intel", "worker", "admission"]
|
||||
replicas: 1
|
||||
|
||||
supply-intel-autoreg:
|
||||
image: supply-intelligence:latest
|
||||
command: ["./supply-intel", "worker", "autoreg"]
|
||||
replicas: 1
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 资源需求
|
||||
|
||||
### 2.1 API Server
|
||||
|
||||
| 资源 | 需求 | 说明 |
|
||||
|------|------|------|
|
||||
| CPU | 1 核 | |
|
||||
| 内存 | 512 MB | |
|
||||
| 存储 | 无 | |
|
||||
|
||||
### 2.2 Worker
|
||||
|
||||
| Worker 类型 | CPU | 内存 | 说明 |
|
||||
|------------|-----|--------|------|
|
||||
| Probe | 1 核 | 512 MB | 同时发起多个 HTTP 请求 |
|
||||
| Discovery | 1 核 | 1 GB | 可能涉及 Playwright 爬取 |
|
||||
| Admission | 2 核 | 2 GB | 测试流水线调用 LLM API,CPU 与内存需求较高 |
|
||||
| Auto-Reg | 1 核 | 512 MB | |
|
||||
|
||||
### 2.3 数据库
|
||||
|
||||
| 资源 | 需求 | 说明 |
|
||||
|------|------|------|
|
||||
| CPU | 2 核 | |
|
||||
| 内存 | 4 GB | |
|
||||
| 存储 | 100 GB | 探针历史 + 审计日志 + 定价数据库 |
|
||||
|
||||
### 2.4 向量数据库
|
||||
|
||||
| 选型 | CPU | 内存 | 存储 | 说明 |
|
||||
|------|-----|--------|------|------|
|
||||
| PGVector | 与 PostgreSQL 共存 | 共存 | 共存 | 推荐,无需额外部署 |
|
||||
| Milvus | 2 核 | 4 GB | 50 GB | 高性能、分布式 |
|
||||
| Qdrant | 1 核 | 2 GB | 30 GB | 轻量、Cloud-native |
|
||||
|
||||
---
|
||||
|
||||
## 3. 监控与运维钩子
|
||||
|
||||
### 3.1 健康检查
|
||||
|
||||
| 端点 | 路径 | 预期响应 | 失败行为 |
|
||||
|------|------|----------|---------|
|
||||
| 存活检查 | `/actuator/health/live` | HTTP 200 | 容器重启 |
|
||||
| 就绪检查 | `/actuator/health/ready` | HTTP 200 | 从负载均衡移除 |
|
||||
| 综合检查 | `/actuator/health` | HTTP 200 + JSON | 触发告警 |
|
||||
|
||||
### 3.2 启动/关闭顺序
|
||||
|
||||
**启动顺序**:
|
||||
1. PostgreSQL 启动完成
|
||||
2. Redis 启动完成
|
||||
3. 向量数据库启动完成
|
||||
4. Worker 启动(执行 migration)
|
||||
5. API Server 启动
|
||||
|
||||
**关闭顺序**:
|
||||
1. 停止接收新 HTTP 请求
|
||||
2. 等待现有请求处理完成(超时 30 秒)
|
||||
3. 停止各 Worker 定时器
|
||||
4. 关闭数据库连接池
|
||||
5. 退出进程
|
||||
|
||||
### 3.3 配置管理
|
||||
|
||||
- 配置文件 `config.yaml` + 环境变量覆盖。
|
||||
- 供应商 API Key 仅通过环境变量传入。
|
||||
- 探针周期、扫描周期、测试用例集路径等可热更新。
|
||||
|
||||
---
|
||||
|
||||
## 4. 灾备设计
|
||||
|
||||
### 4.1 数据库灾备
|
||||
|
||||
| 策略 | 方案 | RTO | RPO |
|
||||
|------|------|-----|-----|
|
||||
| 主库故障 | 自动切换至备库 | < 5 min | < 1 min |
|
||||
| 逻辑损坏 | 从备库恢复 + 审计日志回放 | < 30 min | < 1 min |
|
||||
|
||||
### 4.2 扫描/测试任务灾备
|
||||
|
||||
| 场景 | 处理 |
|
||||
|------|------|
|
||||
| Discovery Worker 故障 | 下一周期自动恢复,扫描任务无状态,不影响生产 |
|
||||
| Admission Worker 故障 | 测试任务缓存在 Redis,恢复后继续执行 |
|
||||
| Probe Worker 故障 | 探针任务缓存在 Redis,恢复后继续执行 |
|
||||
| 向量数据库故障 | 知识库检索降级为文本匹配,不影响核心探针功能 |
|
||||
|
||||
### 4.3 多中心部署
|
||||
|
||||
- 当前阶段为单中心部署。
|
||||
- 探针任务无状态,不依赖中心化调度。
|
||||
- 未来扩展至多中心时,需要解决 PostgreSQL 分布式写入和向量数据库的同步问题。
|
||||
169
tech/GATEWAY_CONSUMER_DECISION_2026-05.md
Normal file
169
tech/GATEWAY_CONSUMER_DECISION_2026-05.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Supply-Intelligence 首期消费闭环决议(2026-05)
|
||||
|
||||
> 状态:当前有效决议
|
||||
> 作用:消除“只有接口定义,没有首期真实消费方与调用落点”的设计歧义。
|
||||
> 适用范围:/home/long/project/立交桥/projects/supply-intelligence/ 下当前收敛规划包。
|
||||
> 真源索引:本决议受 `/home/long/project/立交桥/projects/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md` 纳管;若与历史草案冲突,以真源索引定义的优先级解释。
|
||||
|
||||
## 1. 结论
|
||||
|
||||
首期默认消费闭环采用:
|
||||
- package 发布链路:gateway 作为首期默认消费方,使用 pull `package-changes` + `ack` 机制完成闭环
|
||||
- account 状态链路:立交桥 / supply-api 内部主链路直接读取 `routing-state` 或等价 snapshot,不通过 gateway event ack 闭环
|
||||
|
||||
这意味着必须明确区分两类链路:
|
||||
1. 账号可路由状态链路:查询型消费
|
||||
2. package 发布生效链路:事件型消费
|
||||
|
||||
不得混用以下错误口径:
|
||||
- `published = 已进入 gateway 路由`
|
||||
- `active package = 下游已消费成功`
|
||||
|
||||
正确口径:
|
||||
- `published` 仅表示 supply-intelligence 侧已完成运营确认与 package 激活
|
||||
- 只有 gateway 对 package event 完成 `ack(result=applied)` 后,才能宣称“已被 gateway 消费生效”
|
||||
|
||||
## 2. 首期默认路径
|
||||
|
||||
### 2.1 账号状态链路
|
||||
|
||||
生产主链路:
|
||||
1. probe 执行
|
||||
2. evaluator 分类为 success / explicit_failure / inconclusive
|
||||
3. state machine 生成状态迁移
|
||||
4. 写回 supply account 健康状态与审计
|
||||
5. 立交桥内部路由决策读取 `GET /internal/supply-intelligence/accounts/{account_id}/routing-state`
|
||||
|
||||
说明:
|
||||
- 这是查询型读取,不需要 event ack。
|
||||
- 若调用方读取失败,不回滚 supply-intelligence 已落库状态,只记录消费侧问题。
|
||||
|
||||
### 2.2 package 发布闭环
|
||||
|
||||
生产主链路:
|
||||
1. 运营确认发布 candidate
|
||||
2. package draft -> active
|
||||
3. candidate `test_passed -> published`
|
||||
4. 写入 `gateway_package_events`
|
||||
5. gateway 拉取 `GET /internal/supply-intelligence/gateway/package-changes?cursor=...`
|
||||
6. gateway 应用变更到自身路由/缓存
|
||||
7. gateway 调用 `POST /internal/supply-intelligence/gateway/package-changes/{event_id}/ack`
|
||||
8. `gateway_sync_status` 变为 `applied` 或 `failed`
|
||||
|
||||
说明:
|
||||
- 这是事件型闭环。
|
||||
- `pending` 表示 supply-intelligence 已发布,但 gateway 尚未确认消费。
|
||||
- `failed` 表示 gateway 已消费尝试但未成功,需要运营或工程介入。
|
||||
|
||||
## 3. 为什么不用首期强耦合同步 RPC
|
||||
|
||||
首期明确不采用:
|
||||
- “发布时同步调用 gateway 管理接口,成功后才算发布成功”
|
||||
|
||||
原因:
|
||||
1. 这会把 supply-intelligence 与 gateway 强耦合在单次事务中
|
||||
2. 会把下游暂时不可用放大成上游发布不可用
|
||||
3. 不符合当前“立交桥延伸项目、简洁架构、最小生产闭环”的收敛目标
|
||||
|
||||
因此首期选择:
|
||||
- 上游发布成功与下游消费成功解耦
|
||||
- 用 event + ack 明确消费状态
|
||||
|
||||
## 4. 首期真实代码落点(实现约束)
|
||||
|
||||
以下是首期必须存在的真实调用落点;只有接口定义不算完成。
|
||||
|
||||
### 4.1 supply-intelligence / supply-api 侧
|
||||
- `/home/long/project/立交桥/supply-api/internal/supplyintelligence/publish/service.go`
|
||||
- `PublishCandidate(...)`
|
||||
- `AppendGatewayPackageEvent(...)`
|
||||
- `/home/long/project/立交桥/supply-api/internal/supplyintelligence/integration/http_internal.go`
|
||||
- `GetAccountRoutingState(...)`
|
||||
- `ListGatewayPackageChanges(...)`
|
||||
- `AckGatewayPackageChange(...)`
|
||||
- `/home/long/project/立交桥/supply-api/internal/supplyintelligence/repository/gateway_repo.go`
|
||||
- `InsertGatewayPackageEventTx(...)`
|
||||
- `AckGatewayPackageEventTx(...)`
|
||||
|
||||
### 4.2 gateway 侧(首期必须由消费方实现的真实入口)
|
||||
- 必须存在一个实际消费入口,完成:
|
||||
1. 周期拉取 package changes
|
||||
2. 应用变更
|
||||
3. 回写 ack
|
||||
- 若 gateway 已有内部刷新链路,可复用,但必须补齐 ack 回写
|
||||
- 若 gateway 无现成入口,则新增最小 poller;禁止为了这件事引入 MQ/Kafka/新总线
|
||||
|
||||
## 5. QA 必查真实调用链路
|
||||
|
||||
QA 编码后必须至少验证以下四层:
|
||||
|
||||
### 链路 A:账号状态查询型消费
|
||||
- 定义:`GetAccountRoutingState`
|
||||
- 装配:internal route mounted
|
||||
- 调用:立交桥 / supply-api 实际路由决策点调用该接口或等价函数
|
||||
- 入口:真实请求/真实调用路径可达
|
||||
|
||||
### 链路 B:package 事件发布
|
||||
- 定义:`AppendGatewayPackageEvent`
|
||||
- 装配:publish 流程内注入 repository
|
||||
- 调用:`PublishCandidate` 成功路径真实调用写事件
|
||||
- 入口:运营确认发布入口可真实触达该调用链
|
||||
|
||||
### 链路 C:gateway 拉取消费
|
||||
- 定义:`ListGatewayPackageChanges`
|
||||
- 装配:internal route mounted
|
||||
- 调用:gateway 真实 poller / 既有刷新链调用
|
||||
- 入口:消费方真实任务/刷新入口存在,不是只留 TODO
|
||||
|
||||
### 链路 D:gateway ack 回写
|
||||
- 定义:`AckGatewayPackageChange`
|
||||
- 装配:ack route mounted
|
||||
- 调用:gateway 应用成功/失败后真实回写
|
||||
- 入口:event 状态确实从 `pending -> applied|failed`
|
||||
|
||||
## 6. published / applied 语义约束
|
||||
|
||||
状态含义必须统一:
|
||||
- candidate `published`:上游已完成运营确认
|
||||
- package `active`:上游已允许被消费
|
||||
- gateway sync `pending`:下游尚未确认
|
||||
- gateway sync `applied`:下游已确认消费并应用
|
||||
- gateway sync `failed`:下游消费尝试失败
|
||||
|
||||
禁止:
|
||||
- UI 文案把 `published` 写成“已进路由”
|
||||
- 测试把 `package active` 当成“下游已完成同步”
|
||||
- QA 把 event 表存在当成“消费闭环成立”
|
||||
|
||||
## 7. 与 NewAPI / Sub2API 的边界
|
||||
|
||||
首期不要求 NewAPI / Sub2API 实现 event ack 闭环。
|
||||
它们的首期边界为:
|
||||
- 只读拉取账号状态
|
||||
- 只读拉取已允许暴露的模型/结果
|
||||
|
||||
即:
|
||||
- gateway 是首期必须闭环的事件型消费方
|
||||
- NewAPI / Sub2API 是首期只读适配消费方
|
||||
|
||||
## 8. 门控要求
|
||||
|
||||
在下一轮 QA 设计审查或编码后审查中,若以下任一项缺失,则不得给 APPROVED:
|
||||
1. 没有明确的首期默认消费方
|
||||
2. 没有明确区分查询型链路与事件型链路
|
||||
3. 没有明确 `published != applied`
|
||||
4. 没有真实代码落点要求
|
||||
5. 没有 ack 回写要求
|
||||
|
||||
## 9. 对旧文档的覆盖关系
|
||||
|
||||
本决议用于覆盖旧文档中以下错误或过时口径:
|
||||
- “调用 gateway 管理接口热更新即完成闭环”
|
||||
- “上架成功即下游已生效”
|
||||
- “gateway 会消费”但没有实际消费者与 ack 机制
|
||||
|
||||
如与以下文件冲突,以本决议为准:
|
||||
- /home/long/project/立交桥/projects/supply-intelligence/specs/功能清单.md
|
||||
- /home/long/project/立交桥/projects/supply-intelligence/tech/INTERFACE.md
|
||||
- /home/long/project/立交桥/projects/supply-intelligence/tech/HLD.md
|
||||
- /home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md(若后续未同步更新相应段落,应以本决议补充解释)
|
||||
1013
tech/HLD.md
Normal file
1013
tech/HLD.md
Normal file
File diff suppressed because it is too large
Load Diff
251
tech/IMPLEMENTATION_TASK_BOARD_V1_2026-05.md
Normal file
251
tech/IMPLEMENTATION_TASK_BOARD_V1_2026-05.md
Normal file
@@ -0,0 +1,251 @@
|
||||
# Supply-Intelligence 实现任务板 V1(2026-05)
|
||||
|
||||
> 状态:当前有效
|
||||
> 目的:将当前真源收敛为可直接派工的 Engineer / QA 执行板。
|
||||
> 使用前提:必须先阅读 `/home/long/project/立交桥/projects/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md`。
|
||||
> 当前总门控:APPROVED(允许进入实现)
|
||||
|
||||
## 0. 使用规则
|
||||
|
||||
1. 本任务板不是新的真源,只是执行板。
|
||||
2. 若任务板与以下文件冲突,以以下文件为准:
|
||||
- `/home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md`
|
||||
- `/home/long/project/立交桥/projects/supply-intelligence/tech/GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
- `/home/long/project/立交桥/projects/supply-intelligence/tech/TEST_DESIGN.md`
|
||||
3. 禁止 Engineer 回退到旧 PRD/HLD/INTERFACE/DEPLOYMENT 取实现口径。
|
||||
4. 每个阶段完成后,必须由 QA 按“定义 → 装配 → 调用 → 入口”四层链路做复核。
|
||||
|
||||
## 1. 当前最短闭环路径
|
||||
|
||||
目标:先做出首个最小生产闭环,而不是并行铺开所有模块。
|
||||
|
||||
推荐顺序:
|
||||
1. Phase A:探针与账号状态闭环
|
||||
2. Phase B:发现与 candidate 闭环
|
||||
3. Phase C:准入测试与 draft 生成闭环
|
||||
4. Phase D:发布与 gateway package event + ack 闭环
|
||||
5. Phase E:受控自动补给最小边界
|
||||
6. Phase F:工作台、配置、权限与完善性补齐
|
||||
|
||||
## 2. 阶段任务板
|
||||
|
||||
### Phase A:探针与账号状态闭环
|
||||
|
||||
目标:先让 supply-intelligence 能真实地产生可消费的账号状态。
|
||||
|
||||
#### A-1 数据与领域骨架
|
||||
- Owner:Engineer
|
||||
- 交付物:账号状态、探针日志、审计写入相关 domain/model/repository 基础结构
|
||||
- 完成标准:
|
||||
- 存在 `supply_intelligence_` 前缀表迁移
|
||||
- 探针结果、状态迁移、审计写入模型可落库
|
||||
- QA 验证:检查 schema、repo、service 调用链是否闭合
|
||||
|
||||
#### A-2 探针执行与统一判定
|
||||
- Owner:Engineer
|
||||
- 交付物:probe runner + evaluator
|
||||
- 完成标准:
|
||||
- 200 => success
|
||||
- 401/403 => explicit_failure
|
||||
- 429/5xx/timeout/格式突变 => inconclusive
|
||||
- QA 验证:检查 evaluator 定义、装配、调用与调度入口
|
||||
|
||||
#### A-3 状态机与账号状态快照接口
|
||||
- Owner:Engineer
|
||||
- 交付物:状态迁移逻辑 + `routing-state` 查询接口
|
||||
- 完成标准:
|
||||
- active -> suspended
|
||||
- suspended -> disabled
|
||||
- inconclusive 不触发惩罚性迁移
|
||||
- 存在真实内部查询入口
|
||||
- QA 验证:必须验证 `GET /internal/supply-intelligence/accounts/{account_id}/routing-state` 或等价入口
|
||||
|
||||
#### A-4 Phase A QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- 账号状态链路完成“定义 → 装配 → 调用 → 入口”四层验证
|
||||
- 审计写入与状态写回可追踪
|
||||
- 未引入 Redis / Temporal / WebSocket 作为首期硬依赖
|
||||
|
||||
### Phase B:发现与 candidate 闭环
|
||||
|
||||
目标:能够从已接入供应商拉模型,并产生 candidate。
|
||||
|
||||
#### B-1 供应商适配器与模型拉取
|
||||
- Owner:Engineer
|
||||
- 交付物:SupplierAdapter、registry、GetModels 拉取链路
|
||||
- 完成标准:
|
||||
- 至少支持首批目标供应商
|
||||
- 具备健康探测与模型列表读取
|
||||
- QA 验证:检查 registry 注册、装配、实际调用点
|
||||
|
||||
#### B-2 candidate 生成与去重
|
||||
- Owner:Engineer
|
||||
- 交付物:discovery service + candidate repository
|
||||
- 完成标准:
|
||||
- 能与 `supply_packages` 去重
|
||||
- 新模型生成 discovered candidate
|
||||
- 下架只生成告警,不自动改 package
|
||||
- QA 验证:检查 candidate 创建与下架告警调用链
|
||||
|
||||
#### B-3 Phase B QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- 至少一条真实发现链路打通
|
||||
- candidate 状态初始落点正确
|
||||
- 未扩张到 pricing / prediction / 向量检索
|
||||
|
||||
### Phase C:准入测试与 draft 生成闭环
|
||||
|
||||
目标:让 discovered candidate 可变成 test_passed/test_failed,并生成 draft。
|
||||
|
||||
#### C-1 admission runner
|
||||
- Owner:Engineer
|
||||
- 交付物:标准测试执行器与结果记录
|
||||
- 完成标准:
|
||||
- discovered / retry_pending 可消费
|
||||
- 失败与超时原因可追踪
|
||||
- QA 验证:检查 admission 执行入口和结果写回
|
||||
|
||||
#### C-2 draft package 生成
|
||||
- Owner:Engineer
|
||||
- 交付物:test_passed -> draft package 生成逻辑
|
||||
- 完成标准:
|
||||
- 草稿字段完整
|
||||
- candidate 状态流转闭环
|
||||
- QA 验证:检查 candidate -> draft 的真实调用链
|
||||
|
||||
#### C-3 Phase C QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- 至少一条 candidate 完成 test_passed -> draft
|
||||
- 至少一条 candidate 完成 test_failed -> failure_reason
|
||||
|
||||
### Phase D:发布与 gateway package event + ack 闭环
|
||||
|
||||
目标:打通首个 package 发布最小生产闭环。
|
||||
|
||||
#### D-1 发布服务
|
||||
- Owner:Engineer
|
||||
- 交付物:运营确认发布逻辑
|
||||
- 完成标准:
|
||||
- draft -> active
|
||||
- candidate test_passed -> published
|
||||
- QA 验证:published 语义不得等于 applied
|
||||
|
||||
#### D-2 gateway package events
|
||||
- Owner:Engineer
|
||||
- 交付物:`gateway_package_events` 写入、拉取、ack 回写接口
|
||||
- 完成标准:
|
||||
- 存在 package-changes 列表接口
|
||||
- 存在 ack 接口
|
||||
- ack 后状态可区分 pending/applied/failed
|
||||
- QA 验证:检查 definition / assembly / call / entry 四层
|
||||
|
||||
#### D-3 gateway 消费方最小入口
|
||||
- Owner:Engineer / 对接方
|
||||
- 交付物:真实 poll/apply/ack 入口
|
||||
- 完成标准:
|
||||
- 不是只定义接口
|
||||
- 至少有一个真实消费任务/入口
|
||||
- QA 验证:没有真实入口则本阶段不通过
|
||||
|
||||
#### D-4 Phase D QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- published != applied 证据充分
|
||||
- package event + ack 闭环真实存在
|
||||
- 无“同步调用 gateway 管理接口才算发布成功”的回退实现
|
||||
|
||||
### Phase E:受控自动补给最小边界
|
||||
|
||||
目标:补齐首期最小自动补给能力,但不膨胀为深自动注册。
|
||||
|
||||
#### E-1 自动补给配置与白名单约束
|
||||
- Owner:Engineer
|
||||
- 交付物:auto-supply 配置、阈值、白名单、审批边界
|
||||
- 完成标准:
|
||||
- 非白名单供应商不自动补给
|
||||
- 配置按主仓既有方式存储
|
||||
- QA 验证:检查 guardrail 是否真实生效
|
||||
|
||||
#### E-2 自动补给任务流
|
||||
- Owner:Engineer
|
||||
- 交付物:补给任务创建 / 受理 / 待验证回写
|
||||
- 完成标准:
|
||||
- 低于阈值触发任务
|
||||
- 成功后进入 pending_verify / pending_enable
|
||||
- 不允许直接 active
|
||||
- QA 验证:检查自动启用是否被阻断
|
||||
|
||||
#### E-3 fail-closed
|
||||
- Owner:Engineer
|
||||
- 交付物:通知网关/补给受理/KMS 异常阻断逻辑
|
||||
- 完成标准:
|
||||
- 失败不伪成功
|
||||
- 明文不落日志/DB
|
||||
- QA 验证:检查失败证据和审计闭环
|
||||
|
||||
#### E-4 Phase E QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- 未引入浏览器自动化注册主路径
|
||||
- 未引入验证码编排主路径
|
||||
- 未允许无审批直接自动激活
|
||||
|
||||
### Phase F:工作台、配置、权限与完善性补齐
|
||||
|
||||
目标:补足可操作性与交付完整性,但不得改变前述主链路口径。
|
||||
|
||||
#### F-1 工作台最小读写能力
|
||||
- Owner:Engineer
|
||||
- 交付物:账号页、模型页、待处理页、确认上架、忽略、手动探针
|
||||
- QA 验证:检查关键操作真实连到主链路,不是空按钮
|
||||
|
||||
#### F-2 配置与审计
|
||||
- Owner:Engineer
|
||||
- 交付物:配置读取/修改、审计日志
|
||||
- QA 验证:检查配置生效路径与审计记录
|
||||
|
||||
#### F-3 权限与内部/外部路由边界
|
||||
- Owner:Engineer
|
||||
- 交付物:认证、角色权限、内部接口与外部接口分离
|
||||
- QA 验证:检查 `/internal/supply-intelligence/` 与外部暴露面的边界
|
||||
|
||||
#### F-4 Phase F QA Gate
|
||||
- Owner:QA
|
||||
- 放行条件:
|
||||
- 权限边界清楚
|
||||
- OpenAPI 与真实路由一致
|
||||
- 不新增超范围平台化能力
|
||||
|
||||
## 3. 明确禁止的提前扩张
|
||||
|
||||
以下事项在前述主链路未闭环前,禁止插队进入主开发路径:
|
||||
- pricing / prediction / recommendation
|
||||
- 向量数据库 / 向量检索
|
||||
- SFI 仪表盘
|
||||
- WebSocket 实时推送
|
||||
- 独立 API + worker 集群重部署
|
||||
- 浏览器自动化注册主路径
|
||||
- 验证码编排主路径
|
||||
- 以 Redis / Temporal 为首期硬前置
|
||||
|
||||
## 4. QA 统一复核问题单
|
||||
|
||||
每个阶段 QA 都必须回答:
|
||||
1. 定义是否存在?
|
||||
2. 装配是否存在?
|
||||
3. 调用点是否真实存在?
|
||||
4. 外部/内部入口是否真实挂载?
|
||||
5. 是否出现实施漂移?
|
||||
6. 是否回退到了历史草案口径?
|
||||
|
||||
## 5. 工程启动建议阅读顺序
|
||||
|
||||
1. `/home/long/project/立交桥/projects/supply-intelligence/tech/CURRENT_SOURCE_OF_TRUTH_2026-05.md`
|
||||
2. `/home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md`
|
||||
3. `/home/long/project/立交桥/projects/supply-intelligence/tech/GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
4. `/home/long/project/立交桥/projects/supply-intelligence/tech/TEST_DESIGN.md`
|
||||
5. `/home/long/project/立交桥/projects/supply-intelligence/tech/IMPLEMENTATION_TASK_BOARD_V1_2026-05.md`
|
||||
6. `/home/long/project/立交桥/projects/supply-intelligence/specs/功能清单.md`
|
||||
275
tech/INTERFACE.md
Normal file
275
tech/INTERFACE.md
Normal file
@@ -0,0 +1,275 @@
|
||||
# Supply-Intelligence 核心接口设计
|
||||
|
||||
> 状态说明(2026-05 收敛修订):本文件保留为旧版接口草案,已不再作为当前实现真源。
|
||||
> 当前接口真源以 /home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md 为准。
|
||||
> 以下旧接口定义已废止,不得继续作为实现入口:
|
||||
> - pricing comparison / recommendations / predictions 相关接口
|
||||
> - 与新 candidate 状态机不一致的旧状态枚举
|
||||
> - 未区分 published 与 gateway applied 的旧消费口径
|
||||
|
||||
> 版本:v1.0 | 状态:初稿
|
||||
|
||||
---
|
||||
|
||||
## 1. 内部模块间接口
|
||||
|
||||
### 1.1 ProbeService
|
||||
|
||||
```go
|
||||
type ProbeService interface {
|
||||
// 执行单次探针
|
||||
Probe(ctx context.Context, accountID string) (*ProbeResult, error)
|
||||
// 批量探针(按供应商或全量)
|
||||
ProbeBatch(ctx context.Context, filter ProbeFilter) (*BatchProbeResult, error)
|
||||
// 获取探针结果历史
|
||||
GetProbeHistory(ctx context.Context, accountID string, limit int) ([]ProbeResult, error)
|
||||
// 手动触发掠针(运营干预)
|
||||
TriggerManualProbe(ctx context.Context, accountID string, actorID string) (*ProbeResult, error)
|
||||
}
|
||||
|
||||
type ProbeResult struct {
|
||||
AccountID string
|
||||
Status string // active suspended disabled
|
||||
RiskScore int // 0-100
|
||||
RiskReason string
|
||||
LatencyMs int
|
||||
ResponseCode int
|
||||
CheckedAt time.Time
|
||||
NextCheckAt time.Time
|
||||
}
|
||||
|
||||
type ProbeFilter struct {
|
||||
Platform *string
|
||||
Status *string
|
||||
RiskScoreMin *int
|
||||
RiskScoreMax *int
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 DiscoveryService
|
||||
|
||||
```go
|
||||
type DiscoveryService interface {
|
||||
// 执行单次全网扫描
|
||||
Scan(ctx context.Context) (*ScanResult, error)
|
||||
// 获取最近扫描结果
|
||||
GetLastScan(ctx context.Context) (*ScanResult, error)
|
||||
// 获取候选模型列表
|
||||
ListCandidates(ctx context.Context, filter CandidateFilter) ([]ModelCandidate, error)
|
||||
// 手动触发扫描
|
||||
TriggerManualScan(ctx context.Context, actorID string) (*ScanResult, error)
|
||||
// 忽略候选模型
|
||||
IgnoreCandidate(ctx context.Context, candidateID string, reason string, actorID string) error
|
||||
}
|
||||
|
||||
type ScanResult struct {
|
||||
ScannedAt time.Time
|
||||
Platforms []string
|
||||
NewModels int
|
||||
RemovedModels int
|
||||
Errors []ScanError
|
||||
}
|
||||
|
||||
type ModelCandidate struct {
|
||||
ID string
|
||||
Platform string
|
||||
ModelID string
|
||||
Status string // discovered queued testing test_passed test_failed ignored
|
||||
DiscoveredAt time.Time
|
||||
TestedAt *time.Time
|
||||
TestResult *TestResult
|
||||
}
|
||||
```
|
||||
|
||||
### 1.3 AdmissionService
|
||||
|
||||
```go
|
||||
type AdmissionService interface {
|
||||
// 执行准入测试
|
||||
RunTest(ctx context.Context, candidateID string) (*TestResult, error)
|
||||
// 获取测试结果
|
||||
GetTestResult(ctx context.Context, candidateID string) (*TestResult, error)
|
||||
// 手动确认上架(运营干预)
|
||||
Publish(ctx context.Context, candidateID string, actorID string) error
|
||||
// 强制上架(测试失败但运营确认)
|
||||
ForcePublish(ctx context.Context, candidateID string, reason string, actorID string) error
|
||||
}
|
||||
|
||||
type TestResult struct {
|
||||
CandidateID string
|
||||
Status string // passed failed
|
||||
Dimensions []TestDimension
|
||||
FailedReason *string
|
||||
ExecutedAt time.Time
|
||||
DurationMs int
|
||||
}
|
||||
|
||||
type TestDimension struct {
|
||||
Name string
|
||||
Passed bool
|
||||
Detail string
|
||||
}
|
||||
```
|
||||
|
||||
### 1.4 AccountService
|
||||
|
||||
```go
|
||||
type AccountService interface {
|
||||
// 创建账号(手动或自动)
|
||||
CreateAccount(ctx context.Context, req CreateAccountRequest) (*SupplyAccount, error)
|
||||
// 获取账号信息
|
||||
GetAccount(ctx context.Context, accountID string) (*SupplyAccount, error)
|
||||
// 更新账号状态
|
||||
UpdateStatus(ctx context.Context, accountID string, status string, reason string) error
|
||||
// 轮换密钥
|
||||
RotateKey(ctx context.Context, accountID string, actorID string) error
|
||||
// 列表账号
|
||||
ListAccounts(ctx context.Context, filter AccountFilter) ([]SupplyAccount, error)
|
||||
}
|
||||
|
||||
type SupplyAccount struct {
|
||||
ID string
|
||||
Platform string
|
||||
ProxyID string
|
||||
Status string
|
||||
RiskScore int
|
||||
APIKeyHint string // 密钥前 4 后 4
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
```
|
||||
|
||||
### 1.5 HealthBoardService
|
||||
|
||||
```go
|
||||
type HealthBoardService interface {
|
||||
// 获取供应商健康大盘
|
||||
GetBoard(ctx context.Context, scope BoardScope) (*HealthBoard, error)
|
||||
// 获取模型比价报表
|
||||
GetPricingComparison(ctx context.Context, modelID string) ([]PricingComparison, error)
|
||||
// 获取供应链覆盖率
|
||||
GetCoverage(ctx context.Context) (*CoverageReport, error)
|
||||
// 获取预测分析
|
||||
GetPredictions(ctx context.Context, minConfidence float64) ([]Prediction, error)
|
||||
}
|
||||
|
||||
type HealthBoard struct {
|
||||
Accounts []AccountHealth
|
||||
Candidates []CandidateSummary
|
||||
Coverage float64
|
||||
FreshnessIndex float64
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 外部系统集成接口
|
||||
|
||||
### 2.1 与 Bridge Gateway 集成
|
||||
|
||||
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| 查询账号状态 | `GET /internal/supply-intelligence/accounts/{id}/health` | - | `ProbeResult` | Gateway 路由决策时查询 |
|
||||
| 查询模型定价 | `GET /internal/supply-intelligence/pricing/{model_id}` | - | `PricingInfo` | 动态定价参考 |
|
||||
| 获取推荐供应商 | `GET /internal/supply-intelligence/recommendations` | `?model={model_id}&strategy=cost` | `[]Recommendation` | 智能路由推荐 |
|
||||
|
||||
### 2.2 与 supply-api 集成
|
||||
|
||||
| 方法 | 路径 | 请求 | 响应 | 说明 |
|
||||
|------|------|------|------|------|
|
||||
| 读取账号列表 | `GET /internal/supply/accounts` | - | `[]SupplyAccount` | 探针器获取待检测账号 |
|
||||
| 更新账号状态 | `POST /internal/supply/accounts/{id}/status` | `{"status":"suspended","reason":""}` | `{"success":true}` | 探针结果写回 |
|
||||
| 读取模型列表 | `GET /internal/supply/packages` | - | `[]SupplyPackage` | 扫描比对基准 |
|
||||
| 创建模型 | `POST /internal/supply/packages` | `SupplyPackage` | `{"id":""}` | 准入测试通过后上架 |
|
||||
| 获取审计日志格式 | `GET /internal/supply/audit/schema` | - | `{"schema":{}}` | 审计事件格式一致 |
|
||||
|
||||
---
|
||||
|
||||
## 3. API 接口规范
|
||||
|
||||
### 3.1 REST API 基础
|
||||
|
||||
- **基础路径**: `/api/v1/supply-intelligence/`
|
||||
- **内部路径** (集成模式): `/internal/supply-intelligence/`
|
||||
- **内容类型**: `application/json`
|
||||
- **错误响应格式**:
|
||||
|
||||
```json
|
||||
{
|
||||
"error": {
|
||||
"code": "SI_PRB_4001",
|
||||
"message": "供应商账号不存在",
|
||||
"details": {}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 核心端点
|
||||
|
||||
#### 探针管理
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| GET | `/api/v1/supply-intelligence/probes` | 列表探针结果 |
|
||||
| POST | `/api/v1/supply-intelligence/probes/{account_id}` | 手动触发探针 |
|
||||
| GET | `/api/v1/supply-intelligence/probes/{account_id}/history` | 探针历史 |
|
||||
|
||||
#### 扫描与发现
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| POST | `/api/v1/supply-intelligence/discovery/scan` | 手动触发全网扫描 |
|
||||
| GET | `/api/v1/supply-intelligence/discovery/candidates` | 列表候选模型 |
|
||||
| GET | `/api/v1/supply-intelligence/discovery/candidates/{id}` | 获取候选模型详情 |
|
||||
| POST | `/api/v1/supply-intelligence/discovery/candidates/{id}/ignore` | 忽略候选模型 |
|
||||
|
||||
#### 准入测试
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| POST | `/api/v1/supply-intelligence/admission/{candidate_id}/test` | 手动执行准入测试 |
|
||||
| GET | `/api/v1/supply-intelligence/admission/{candidate_id}/result` | 获取测试结果 |
|
||||
| POST | `/api/v1/supply-intelligence/admission/{candidate_id}/publish` | 确认上架 |
|
||||
| POST | `/api/v1/supply-intelligence/admission/{candidate_id}/force-publish` | 强制上架 |
|
||||
|
||||
#### 账号管理
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| GET | `/api/v1/supply-intelligence/accounts` | 列表账号 |
|
||||
| POST | `/api/v1/supply-intelligence/accounts` | 创建账号 |
|
||||
| GET | `/api/v1/supply-intelligence/accounts/{id}` | 获取账号 |
|
||||
| POST | `/api/v1/supply-intelligence/accounts/{id}/rotate-key` | 轮换密钥 |
|
||||
| POST | `/api/v1/supply-intelligence/accounts/{id}/status` | 更新状态 |
|
||||
|
||||
#### 健康大盘
|
||||
|
||||
| 方法 | 路径 | 描述 |
|
||||
|------|------|------|
|
||||
| GET | `/api/v1/supply-intelligence/health-board` | 获取健康大盘 |
|
||||
| GET | `/api/v1/supply-intelligence/pricing/{model_id}/comparison` | 模型比价 |
|
||||
| GET | `/api/v1/supply-intelligence/coverage` | 供应链覆盖率 |
|
||||
| GET | `/api/v1/supply-intelligence/predictions` | 预测分析 |
|
||||
|
||||
### 3.3 错误码定义
|
||||
|
||||
| 错误码 | HTTP 状态 | 说明 |
|
||||
|---------|-----------|------|
|
||||
| `SI_PRB_4001` | 404 | 供应商账号不存在 |
|
||||
| `SI_PRB_4002` | 429 | 探针频率过高,请等待 |
|
||||
| `SI_DIS_4001` | 404 | 候选模型不存在 |
|
||||
| `SI_DIS_4002` | 409 | 候选模型状态不允许忽略 |
|
||||
| `SI_ADM_4001` | 404 | 准入测试任务不存在 |
|
||||
| `SI_ADM_4002` | 409 | 准入测试正在执行中 |
|
||||
| `SI_ADM_4003` | 400 | 测试未通过,无法上架 |
|
||||
| `SI_ACC_4001` | 404 | 账号不存在 |
|
||||
| `SI_ACC_4002` | 409 | 账号状态不允许此操作 |
|
||||
| `SI_ACC_4003` | 403 | 无权执行此操作 |
|
||||
| `SI_BRD_4001` | 400 | 查询参数无效 |
|
||||
|
||||
### 3.4 WebSocket 接口
|
||||
|
||||
**路径**: `/ws/v1/supply-intelligence/board`
|
||||
|
||||
- 运营工作台订阅后,实时推送探针结果、候选模型变更、状态变更待办。
|
||||
- 心跳间隔 30 秒。
|
||||
355
tech/TEST_DESIGN.md
Normal file
355
tech/TEST_DESIGN.md
Normal file
@@ -0,0 +1,355 @@
|
||||
# Supply Intelligence 测试设计方案
|
||||
|
||||
> 状态说明(2026-05 收敛修订):本文件已转为“收敛后测试门禁文档”,必须按新基线解释。
|
||||
> 若与旧 PRD/HLD/INTERFACE 的测试口径冲突,以 /home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md 与最新 PM 基线为准。
|
||||
> 以下旧测试口径不得继续作为放行依据:
|
||||
> - 以独立重部署、向量数据库、WebSocket、预测/比价能力为默认测试前提
|
||||
> - 将自动注册深链路视为本期不可降期的默认主路径
|
||||
> - 将 published 等同于 gateway 已消费生效
|
||||
|
||||
> 版本:v1.0
|
||||
> 日期:2026-04-27
|
||||
> 状态:初稿
|
||||
> 覆盖:AC-01 ~ AC-12、异常/边缘流程 FP-01 ~ FP-10、场景 S1~S4
|
||||
|
||||
---
|
||||
|
||||
## 1. 测试策略
|
||||
|
||||
### 1.1 测试分层模型
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ E2E Tests (黑盒) │
|
||||
│ 场景:从探针调度到状态变更、从发现到上架全链路 │
|
||||
│ 工具:Go test + httptest + 自制 E2E runner │
|
||||
└─────────────────────────────────────────────────┘
|
||||
▲
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Integration Tests (灰盒) │
|
||||
│ 场景:Service 间协作、异步任务队列、外部 API Mock│
|
||||
│ 工具:Go test + testify + sqlmock + gock │
|
||||
│ 覆盖率门槛:service ≥ 80%, handler ≥ 80% │
|
||||
└─────────────────────────────────────────────────┘
|
||||
▲
|
||||
┌─────────────────────────────────────────────────┐
|
||||
│ Unit Tests (白盒) │
|
||||
│ 场景:状态机逻辑、探针评估、风险评分计算 │
|
||||
│ 工具:Go test + testify + gomock │
|
||||
│ 覆盖率门槛:domain ≥ 70% │
|
||||
└─────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 1.2 测试通过标准
|
||||
|
||||
| 维度 | 标准 |
|
||||
|------|------|
|
||||
| 覆盖率 | domain ≥ 70%, service/handler ≥ 80% |
|
||||
| 模块 A(探针) | AC-01 ~ AC-03 全部通过 |
|
||||
| 模块 B(发现) | AC-04 ~ AC-05 全部通过 |
|
||||
| 模块 C(准入测试) | AC-06 ~ AC-07 全部通过 |
|
||||
| 模块 D(受控自动补给) | AC-08 ~ AC-09 全部通过(按首期最小边界解释) |
|
||||
| 模块 E(工作台) | AC-10 ~ AC-12 全部通过 |
|
||||
| 异常/边缘流程 | FP-01 ~ FP-10 全部有验证测试 |
|
||||
| 误报率 | 7 天连续运行 false positive ≤ 1% |
|
||||
|
||||
### 1.3 外部依赖 Mock
|
||||
|
||||
| 依赖 | Mock 方案 | 工具 |
|
||||
|------|---------|------|
|
||||
| **供应商 API(探针目标)** | Mock server 返回 200/401/403/429/500 | gock |
|
||||
| **供应商模型列表 API** | Mock 返回 JSON 模型列表 | gock |
|
||||
| **供应商补给接口 / 人工补录入口** | Mock 返回受理成功/400/500 | gock |
|
||||
| **通知网关(飞书/邮件)** | Mock server 接收通知或确认消息 | httptest |
|
||||
| **KMS 服务** | Mock 加密/解密逻辑 | 接口层 Mock |
|
||||
| **Job Scheduler / 主仓调度器** | 使用主仓调度抽象或本地调度测试桩 | go test + test double |
|
||||
| **supply-api 数据库** | sqlmock 拦截读写 | go-sqlmock |
|
||||
|
||||
---
|
||||
|
||||
## 2. 模块 A 测试用例(供应商品质探针)
|
||||
|
||||
### AC-01 探针覆盖度
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TA-01-01 | 15 分钟内探针覆盖率 ≥99% | Functional | Given 100 条 active/suspended 账号 When 15min 后统计 Then ≥99 条被探针 |
|
||||
| TA-01-02 | suspended 账号同等探针 | Functional | Given suspended 账号 When 探针执行 Then 同样被覆盖 |
|
||||
| TA-01-03 | 暂停探针账号不被覆盖 | Edge | Given 账号设置 pause_probe=true When 探针执行 Then 该账号被跳过 |
|
||||
|
||||
### AC-02 状态变更正确性
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TA-02-01 | active → suspended(1次401) | Happy Path | Given active 账号 When 连续 1 次返回 401 Then 60s 内状态变为 suspended |
|
||||
| TA-02-02 | suspended → disabled(连续3次401) | Happy Path | Given suspended 账号 When 连续 3 次返回 401 Then 60s 内状态变为 disabled |
|
||||
| TA-02-03 | 429 单次不改变状态 | Edge | Given active 账号 When 返回 429 一次 Then 15min 内状态保持 active |
|
||||
| TA-02-04 | 指数退避重试逻辑 | Functional | Given 返回 429 When 探针执行 Then 按 1→2→4min 退避重试 |
|
||||
| TA-02-05 | 状态机不允许 active→disabled 直变 | Edge | Given active 账号 When 连续 3 次失败 Then 不会直接变为 disabled(必须先 suspended) |
|
||||
| TA-02-06 | 手动暂停账号状态不自动变更 | Edge | Given 账号 pause_probe=true When 供应商返回异常 Then 状态不变 |
|
||||
|
||||
### AC-03 误报率
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TA-03-01 | 7 天误报率 ≤1% | Long Run | Given 100 条正常账号 When 连续运行 7 天 Then 误变更次数 ≤7 |
|
||||
| TA-03-02 | 探针与手动操作并发 | Concurrency | Given 手动修改状态的同时 When 探针执行 Then 乐观锁冲突处理正确 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 模块 B 测试用例(全网模型发现)
|
||||
|
||||
### AC-04 新模型发现延迟
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TB-04-01 | 新模型在 2 扫描周期内被发现 | Functional | Given 供应商新增 model_id When 扫描执行 Then 2h 内 model_candidates 出现 discovered 记录 |
|
||||
| TB-04-02 | 模型比对去重正确 | Functional | Given 已存在的 active model When 全网扫描 Then 不会重复创建 candidate |
|
||||
| TB-04-03 | 模型下架告警触发 | Functional | Given active package 对应的 model_id 从供应商列表消失 When 2 扫描周期后 Then 运营工作台出现下架告警 |
|
||||
|
||||
### AC-05 已下架模型告警
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TB-05-01 | 下架模型不自动变更 package 状态 | Edge | Given model_id 消失 When 扫描执行 Then package 状态保持 active,生成告警 |
|
||||
| TB-05-02 | 分页获取完整模型列表 | Functional | Given 供应商返回分页 When 扫描 Then 正确处理所有分页数据 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 模块 C 测试用例(模型准入测试)
|
||||
|
||||
### AC-06 准入测试通过
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TC-06-01 | discovered → test_passed + 草稿生成 | Happy Path | Given discovered candidate When 测试全部通过 Then 状态 test_passed,supply_package 草稿生成 |
|
||||
| TC-06-02 | 草稿字段完整性 | Functional | Given 草稿生成 When 检查字段 Then platform/model/price/suggested 正确 |
|
||||
| TC-06-03 | 准入测试 30 分钟内完成 | Performance | Given discovered candidate When 测试执行 Then ≤30min 完成 |
|
||||
|
||||
### AC-07 准入测试失败
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TC-07-01 | discovered → test_failed | Negative | Given discovered candidate When 测试返回 500 Then 30min 内状态 test_failed,failure_reason 非空 |
|
||||
| TC-07-02 | 超时视为失败 | Edge | Given 测试用例 60s 无响应 When Then 整体标记为 test_failed,reason = timeout |
|
||||
| TC-07-03 | 测试账号 suspended 时任务失败 | Edge | Given 测试账号变为 suspended When 准入测试执行 Then 任务标记 test_failed,reason = test_account_unavailable |
|
||||
| TC-07-04 | ignore 账号 7 天内不重扫 | Edge | Given 运营标记 ignore When 7 天内扫描 Then 该 candidate 不出现 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 模块 D 测试用例(受控自动补给)
|
||||
|
||||
### AC-08 受控自动补给触发与落单
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TD-08-01 | 可用账号数 < 阈值时触发补给任务 | Functional | Given 白名单供应商的可用账号数 < 阈值 When 系统检测 Then 10min 内生成补给任务或补给申请 |
|
||||
| TD-08-02 | 非白名单供应商不自动补给 | Guardrail | Given 非白名单供应商账号不足 When 系统检测 Then 不自动触发补给,仅记录告警或人工待办 |
|
||||
| TD-08-03 | 补给结果进入待验证/待启用 | Happy Path | Given 补给流程受理成功 When 补给完成 Then 新账号或候选资源进入 pending_verify / pending_enable 等受控状态,而非直接 active |
|
||||
| TD-08-04 | 补给结果关联 task | Functional | Given 补给任务完成 When 检查任务记录 Then auto_supply_tasks 或等价任务状态为 completed/pending_verify |
|
||||
|
||||
### AC-09 受控自动补给 fail-closed
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TD-09-01 | 通知/补给网关不可用时 fail-closed | Resilience | Given 通知网关或补给受理接口返回 503 When 补给执行 Then 60s 内任务 failed,审计日志完整,无虚假成功 |
|
||||
| TD-09-02 | 补给接口返回 400 | Edge | Given 补给请求参数非法或资源已存在 When 补给执行 Then 任务 failed,不重复盲目重试 |
|
||||
| TD-09-03 | KMS 不可用时 fail-closed | Resilience | Given KMS 超时 When 凭证加密步骤执行 Then 60s 内任务 failed,明文凭证不出现在日志/DB |
|
||||
| TD-09-04 | 无审批/越权配置时阻断自动启用 | Guardrail | Given 缺少审批或超出受控边界 When 补给结果回写 Then 保持 pending_verify / pending_enable,不允许直接进入 active |
|
||||
|
||||
---
|
||||
|
||||
## 6. 模块 E 测试用例(运营工作台)
|
||||
|
||||
### AC-10 审计日志完整性
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TE-10-01 | 状态变更 5s 内写入审计 | Performance | Given 状态变更 When 执行完成 Then ≤5s 审计记录存在 |
|
||||
| TE-10-02 | 审计字段完整性 | Functional | Given 审计记录 When 检查 Then 包含 object_type/id/action/before_state/after_state/request_id |
|
||||
| TE-10-03 | 探针执行记录审计 | Functional | Given 探针执行 When 完成 Then probe_execution_logs 有记录 |
|
||||
|
||||
### AC-11 运营工作台干预
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TE-11-01 | 确认上架 draft → active | Happy Path | Given draft package When 点击确认 Then 3s 内变为 active |
|
||||
| TE-11-02 | 忽略模型 7 天内不出现 | Edge | Given 点击忽略 When Then 7 天内 candidate 不出现在待处理列表 |
|
||||
| TE-11-03 | 手动触发单账号探针 | Functional | Given 运营手动触发 When Then 立即执行探针,结果可见 |
|
||||
| TE-11-04 | 并发操作冲突处理 | Concurrency | Given 同时点击确认和忽略 When Then 返回 409,只一个生效 |
|
||||
|
||||
### AC-12 配置热更新
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TE-12-01 | 探针周期修改 60s 内生效 | Functional | Given 修改探针周期 When 下发配置 Then 60s 后新周期生效 |
|
||||
|
||||
---
|
||||
|
||||
## 7. 异常/边缘流程测试(FP-01 ~ FP-10)
|
||||
|
||||
| 用例 ID | 场景 | 验证点 | 预期行为 |
|
||||
|---------|------|-------|---------|
|
||||
| TFP-01 | 供应商探针 DNS/TCP 超时 | 状态不变 | 标记 inconclusive,指数退避,不触发状态变更 |
|
||||
| TFP-02 | 供应商返回空/格式突变 | 状态不变 | 解析失败标记 inconclusive,记录日志 |
|
||||
| TFP-03 | 探针与手动操作并发 | 乐观锁 | 更新失败,探针记录冲突日志,下次覆盖 |
|
||||
| TFP-04 | 准入测试期间测试账号 suspended | 任务标记失败 | 任务标记 test_failed,reason = test_account_unavailable |
|
||||
| TFP-05 | 补给接口返回 400 或资源冲突 | 任务失败 | 任务 failed,不重复盲目重试,审计记录完整 |
|
||||
| TFP-06 | 补给成功但验证/启用失败 | pending 不变 | 账号保持 pending_verify/pending_enable,任务标记 verify_failed,触发告警 |
|
||||
| TFP-07 | 供应商模型列表分页 500 | 整体不中断 | 已获取部分正常处理,失败页下次重试 |
|
||||
| TFP-08 | 探针期间数据库不可用 | 任务失败重试 | 探针任务失败,连续 5 次失败后暂停批次,触发系统告警 |
|
||||
| TFP-09 | 确认上架与忽略并发 | 409 冲突 | 只有一个生效,返回 409 |
|
||||
| TFP-10 | KMS 不可用时注册 | 明文不落盘 | 加密步骤阻塞/失败,明文凭证不出现 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 灰度发布验证计划
|
||||
|
||||
### 8.1 各 Phase 验证内容
|
||||
|
||||
| Phase | 交付内容 | 通过标准 | 依赖项 |
|
||||
|-------|---------|---------|--------|
|
||||
| **Phase 1** | 模块 A(探针)+ 模块 E 只读视图 | AC-01~AC-03, AC-10~AC-11(只读部分) | 主仓调度能力或本地调度测试桩 |
|
||||
| **Phase 2** | 模块 B(发现)+ 模块 C(准入测试) | AC-04~AC-07 | Phase 1 + 供应商 API 清单 |
|
||||
| **Phase 3** | 模块 D(受控自动补给)+ 模块 E 完整 | AC-08~AC-12 | Phase 1+2 + KMS/通知与补给受理链路就绪 |
|
||||
|
||||
### 8.2 灰度门禁
|
||||
|
||||
每次 Phase 升级前:
|
||||
- [ ] 全部 AC 测试用例通过
|
||||
- [ ] 覆盖率达标
|
||||
- [ ] 灰度开关独立验证(每个开关可单独打开/关闭)
|
||||
- [ ] 回滚条件演练(误报率>5% / 状态变更导致错误率上升>2%)
|
||||
|
||||
---
|
||||
|
||||
## 9. 回归测试集
|
||||
|
||||
### 9.1 快速回归(每次 PR,~10 分钟)
|
||||
|
||||
```
|
||||
TA-01-01, TA-02-01, TA-02-02, TA-02-05,
|
||||
TB-04-01, TC-06-01, TC-07-01,
|
||||
TD-08-01, TD-09-01,
|
||||
TE-10-01, TE-11-01
|
||||
共 11 条
|
||||
```
|
||||
|
||||
### 9.2 完整回归(Phase 升级,~45 分钟)
|
||||
|
||||
```
|
||||
TA-01-01 ~ TA-03-02(全 8 条)
|
||||
TB-04-01 ~ TB-05-02(全 4 条)
|
||||
TC-06-01 ~ TC-07-04(全 4 条)
|
||||
TD-08-01 ~ TD-09-03(全 4 条)
|
||||
TE-10-01 ~ TE-12-01(全 7 条)
|
||||
TFP-01 ~ TFP-10(全 10 条)
|
||||
共 37 条
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 技术栈与集成约束验证
|
||||
|
||||
### 10.1 统一技术栈与双运行模式验证
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TSI-RUN-01 | 独立运行模式启动 | Happy Path | Given 独立 `config.yaml` 与独立数据库/Redis When 启动 `cmd/supply-intelligence/main.go` Then `/actuator/health/ready` 返回 200,`/api/v1/supply-intelligence/*` 可访问 |
|
||||
| TSI-RUN-02 | 集成运行模式挂载 | Integration | Given supply-api 主进程加载 `IntegrationPlugin` When 启动 Then `/internal/supply-intelligence/*` 路由与后台任务注册成功 |
|
||||
| TSI-RUN-03 | 配置分离加载 | Functional | Given 独立模式与集成模式分别启动 When 读取配置 Then 独立模式只加载自身配置,集成模式合并主项目配置且不覆盖无关模块 |
|
||||
| TSI-RUN-04 | 数据库前缀隔离 | Structural | Given 执行迁移 When 检查 schema Then 仅创建 `supply_intelligence_` 前缀表 |
|
||||
|
||||
### 10.2 独立运行与集成运行验证
|
||||
|
||||
### 10.3 IntegrationPlugin 与模块挂载验证
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TSI-PLG-01 | IntegrationPlugin 注册 HTTP 路由 | Integration | Given 集成模式 When 插件注册 Then Probe/Discovery/Admission/AutoReg/OpsWorkBench 路由挂载成功 |
|
||||
| TSI-PLG-02 | 模块开关生效 | Functional | Given `enabled_modules` 关闭某模块 When 启动 Then 对应路由/worker 不注册,其他模块可用 |
|
||||
| TSI-PLG-03 | 集成模式共享资源 | Integration | Given supply-api 注入共享 DB/Redis/logger When 插件启动 Then 使用共享资源且不重复初始化冲突依赖 |
|
||||
|
||||
### 10.3 OpenAPI 契约验证
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TSI-OAS-01 | OpenAPI 文档可访问 | Functional | Given 服务启动 When 请求 `/openapi.json` 或 `/docs` Then 返回 200 且包含探针、发现、准入测试、运营工作台接口 |
|
||||
| TSI-OAS-02 | 路由与 OpenAPI 一致 | Contract | Given 导出的 OpenAPI 文档 When 对照 HTTP 路由 Then 请求/响应/错误码与实现一致,无缺失公开接口 |
|
||||
| TSI-OAS-03 | 集成前缀可配置 | Contract | Given 集成模式配置内部前缀 When 导出文档 Then 文档反映 `/internal/supply-intelligence/` 前缀或明确区分暴露面 |
|
||||
|
||||
### 10.4 NewAPI / Sub2API 适配层验证
|
||||
|
||||
| 用例 ID | 描述 | 类型 | 验证条件 |
|
||||
|---------|------|------|---------|
|
||||
| TSI-ADP-01 | 供应商状态同步适配 | Contract | Given NewAPI/Sub2API 拉取供应商状态 When 调用标准化接口 Then 返回字段稳定、延迟满足约束、状态映射正确 |
|
||||
| TSI-ADP-02 | 模型列表推送适配 | Contract | Given 外部系统拉取模型列表 When 调用 `/models` Then 只返回已发现且允许暴露的数据,字段与约定一致 |
|
||||
| TSI-ADP-03 | 账号状态适配边界 | Contract | Given 外部系统读取账号状态 When 通过适配层执行 Then 仅返回允许暴露的状态字段,不暴露凭证/探针日志/内部风险细节 |
|
||||
|
||||
---
|
||||
|
||||
## 11. 发布门禁与阶段结论
|
||||
|
||||
### 11.1 发布门禁检查表
|
||||
|
||||
以下门禁项全部通过前,不得认定达到生产要求:
|
||||
|
||||
- [ ] 独立运行 / 集成运行两种模式均完成启动验证,路由、worker、内部接口真实挂载
|
||||
- [ ] `IntegrationPlugin`、OpenAPI、NewAPI/Sub2API 适配层合同测试全部通过
|
||||
- [ ] 凭证保护经日志/DB/异常路径验证无明文,KMS 不可用时 fail-closed
|
||||
- [ ] 受控自动补给链路具备白名单限制、阈值触发、审批/待验证边界、重复提交阻断与审计留痕
|
||||
- [ ] 状态机迁移、审计写入、Gateway package event + ack、外部只读适配链路完成一致性验证
|
||||
- [ ] 首次生产放量场景遵循“只告警不自动变更状态”,并验证撤销与人工接管流程
|
||||
- [ ] 调度器失效、补给受理失败、外部适配越权、错误状态传播四类高风险回归通过
|
||||
- [ ] 至少一条探针、一条模型发现、一条准入测试、一条受控自动补给链路完成端到端验证
|
||||
|
||||
### 11.2 阶段门控结论
|
||||
|
||||
**当前结论:APPROVED(设计已可进入 Engineer 实现)**
|
||||
|
||||
**结论解释:**
|
||||
- 本文档首页所述“收敛后测试门禁文档”口径已生效。
|
||||
- 当前放行依据不再是旧 HLD/PRD/INTERFACE/DEPLOYMENT,而是:
|
||||
- `/home/long/project/立交桥/projects/supply-intelligence/tech/BASELINE_TECHLEAD_V2.md`
|
||||
- `/home/long/project/立交桥/projects/supply-intelligence/tech/GATEWAY_CONSUMER_DECISION_2026-05.md`
|
||||
- 因此,本节不再沿用历史性 `REQUEST_CHANGES` 作为当前总门控。
|
||||
|
||||
**当前仍需在实现阶段持续验证的高风险项:**
|
||||
- 凭证保护必须能证明 fail-closed,且日志/审计/异常路径无明文泄漏。
|
||||
- 状态同步、审计写入、package event + ack 必须形成可追踪闭环。
|
||||
- 关键链路必须能完成“定义 → 装配 → 调用 → 入口”四层验证,不能只停留在接口存在。
|
||||
- 自动补给按首期最小边界解释:允许白名单供应商、阈值触发、任务化补给、待验证/待启用;不把浏览器自动化深链路作为首期阻断门槛。
|
||||
|
||||
**实现前约束:**
|
||||
- 若实现与 `BASELINE_TECHLEAD_V2.md` 或 `GATEWAY_CONSUMER_DECISION_2026-05.md` 冲突,应以两者为准并回退旧测试假设。
|
||||
- 若下游消费方未落真实 poll/apply/ack 入口,不得宣称 package 发布链路已完成。
|
||||
- 若 NewAPI/Sub2API 适配超出“只读/受控暴露边界”,应判定为实施漂移。
|
||||
|
||||
**重新转为 REQUEST_CHANGES / BLOCKED 的条件:**
|
||||
- 实现阶段发现 published/applied 再次混淆。
|
||||
- gateway 消费闭环缺少真实消费方入口或 ack 回写。
|
||||
- 自动补给被重新扩张为首期深自动注册硬门槛。
|
||||
- 核心链路无法提供四层调用链证据。
|
||||
|
||||
---
|
||||
|
||||
## 12. 性能与安全测试
|
||||
|
||||
### 12.1 性能基准
|
||||
|
||||
| 指标 | 目标值 | 测试方法 |
|
||||
|------|-------|---------|
|
||||
| 探针执行(单账号) | <2s | 计时 1000 次取 P99 |
|
||||
| 全网扫描(10 供应商) | <5min | 从调度触发到完成计 |
|
||||
| 准入测试(5 用例) | <30min P99 | 从 discovered 到 test_passed/failed |
|
||||
| 供应商状态查询 API | <50ms P99 | 并发 100 请求 |
|
||||
| 审计日志写入 | <1s P99 | 单次变更后计时 |
|
||||
|
||||
### 12.2 安全测试
|
||||
|
||||
| 测试项 | 方法 | 验证 |
|
||||
|-------|------|------|
|
||||
| 凭证明文保护 | 检查日志/DB/内存 dump | 无明文凭证 |
|
||||
| KMS 密钥轮换 | Mock KMS 不可用 | fail-closed,不暴露明文 |
|
||||
| 供应商 API 限流绕过 | 连续探针超限 | 正确触发 rate limit |
|
||||
| 注册接口重复提交 | 并发同一邮箱注册 | 只有一次成功,其余 failed |
|
||||
Reference in New Issue
Block a user