PROC-04-004 Platform与Media及Runtime架构审计(2026-10-28)
2026-10-28跨项目架构复盘的只读审计附件,事实与建议分列,不构成批准决策。
本页是跨项目架构深度复盘的过程附件。观察事实、静态推断和建议分别阅读;建议不构成已批准决策,不修改既有ADR/PRD。版本、线上取证与未验证范围统一见审计证据。
源码链接固定到审计记录的完整提交;未提交工作副本、无法固定的本地材料明确标注,不以相近提交替代。固定链接只证明所引源码,不证明部署、性能或真实付费验收。
本报告是只读源码审计,辅以主审提供的 SSH docker image label 核验;不代表业务端到端线上验收。不改代码、不启动服务、不访问生产库、不执行付费请求。用户已澄清“exa”为笔误,所关心的是 Platform 登录鉴权;代码中的 exa_ 恰好是 execution authorization 的引用前缀。
结论
公共底座已经存在,但“服务权威”“可复用 SDK”“产品接线”“已部署版本”未同步演进。此刻最重要的工作不是再建一套统一平台,而是固定当前唯一身份、执行和素材契约,然后把现有公共实现整理为薄客户端与统一失败语义。Runtime 的旧 FileReferenceClient 不能直接作为当前统一素材 SDK;新运营后台也不能拿一个全能产品 Key 代替操作者权限。
优先处理的事实:
- Platform
/identity证明用户会话有效,返回全局角色,不证明用户是 Drama/Studio 项目 owner,更不代表运营权限。 - Platform main 已提供非流式文本原请求恢复。线上image label指向的ecac00e提交不含该实现,但实际二进制包含合同/路由,外网无凭据GET该路由返回401 PLATFORM_PRODUCT_REQUIRED,假路由则回SPA。线上文本恢复路由确实存在;本轮未持授权测试恢复内容。确定的问题是制品来源元数据与实际二进制不一致。
- Media 新源码已切换到
/internal/assets/v1+oceanway.assets.v1;主审在 pic-vps 观察到 9220708 统一素材部署实例及统一桶配置,另一个主机仍有 7099bc2 旧 FileOwner 实例。公共 media.oceanway.tech 的精确反代映射未直接核验。Runtime main 仍调用旧接口。两代协议并存是事实,具体线上影响取决于实际端点;不能误报成 Runtime 当前线上一定 404。 - 统一素材服务新源码已经覆盖原件、去重、配额、跨产品引用、短签名读取、删除和恢复;旧 FileOwner 实例
7099bc2不提供这些新能力,但其存在不能否定另一 Media 目标已经部署统一素材。新产品再实现存储原件/配额/云桶管理,会绕过这套权威。 - Drama 在枚举中存在,但项目索引/写入两端仍硬编码 Studio/Commerce。接入不能只配置
product=drama就声称完成。 - Runtime 的持久任务和不重复派发能力可复用;宿主鉴权、业务目标与 ResultSink 仍必须产品实现,不能把所有编排及产品领域都搬到 Platform。
本轮版本边界
| 工程/位置 | 本轮观察 | 可确认 / 不可推断 |
|---|---|---|
| oceanway-platform | main db801bf,干净 | 当前本地主线 |
| oceanway-platform | ecac00e,干净;提交已是 main 祖先 | 线上 image label 指向它,但实际二进制含后续文本恢复字符串,不能当作完整运行源码证明 |
| temp-media-gateway | 7bf5cc1,干净,new-api-new-oceanway 工作树 | 新统一素材与媒体生产方源码;另已定位后续9220708部署实例 |
| pic-vps统一素材实例 | 9220708b503778fd61af4309f3c5d5deb7186e3b;S3_BUCKET=oceanway-media-assets-cn | 主审只读SSH确认实例/标签/桶;公共status匹配OceanWay Media,精确反代映射未直接核验 |
| 某主机旧 FileOwner 运行实例 image label | 7099bc2a723aba885072538c8668f1c2e89e9ac7 | 主审只读 SSH 确认 running;未证明它是 media.oceanway.tech 路由目标;git show可定位旧API |
| oceanway-media-gateway | main 8cdf707,干净 | 旧独立供应网关,历史三桶方案;本轮不把它当现行统一素材主链 |
| oceanway-runtime | main 9ff79e6,干净 | 当前公共包主线;发布/宿主采用各自核验 |
oceanway-runtime 未提交候选(未固定源码链接) | HEAD 1e75740;大量未提交修改,包括新增 execution-authorization.ts、run-control schema | 进行中的另一候选,不能当 main 已具备能力,也不应再平行实现同类授权存储 |
ecac00e..db801bf增量包括38f4655文本原请求恢复。源码ecac00e不含相关文件/GET路由,实际线上binary却包含,且无凭据GET已命中真实鉴权401(假路由回SPA)。因此image label不足以证明运行源码。主审记录binary SHA256为4d4068f5dd49e4c84344964cc741a42d923b27b68bd103a05abeb08377b10834;需要补构建输入来源。本轮未用真实授权恢复任务。
当前请求与权限链
1. 浏览器身份与产品权限是两个不同判断
/api/platform/v1/identity 仅挂 PlatformSessionAuth():
- router/platform-router.go:43
- middleware/platform_identity.go:31:要求唯一会话 Cookie,验证 host/session,注入 user。
- controller/platform_identity.go:41:重新验证会话,查询角色,76 行返回 user、session、product_roles、platform_roles、admin_actions。
这里没有 product 参数,也没有某产品的准入动作。product_roles 的格式为 scope:role,所有 scope 一起返回。调用方若在 identity 成功后直接 Role=owner,它是在自己创建业务权限,不能说 Platform 已批准 owner。这不等价于“所有普通用户都不应能使用产品”:普通产品使用是否开放,需要产品准入规则;项目 owner 仍应来自具体对象归属。
Platform 已有可复用权威:
- service/platform_identity_authorization.go:121:
AuthorizePlatformProductRole(tx, identity, scope, action)。 - 同文件 36 行:平台 Admin 动作逐次授权;root 全权;原生 admin 仅自动拥有 settings/pricing/orders 的 read,写动作依 role grants。
- 同文件 83 行:
admin_actions是导航提示,不能代替每次请求的服务端授权。 - middleware/platform_identity.go:138、154:已有 Admin / ProductRole middleware。
推荐公共包输出可信 SessionPrincipal 与动作授权结果,不输出自动 owner。产品负责把全局 subject 映射到本地账号/成员/项目权限。运营后台应使用 Platform 的 operator session + 明确的 product/action/resource 委托契约,产品管理 API 再检查对象与作用域;不要共享 root Cookie 或让前端持有 product key。
2. 产品服务凭据不是用户登录凭据,也不是任意用户扣费权
- service/platform_identity.go:439:正式 product key 为 key ID + secret,查数据库 hash、revoked_at、actions。
- 同文件 283:产品名仍固定 studio/drama/commerce。
- middleware/platform_identity.go:55:每个入口要求具体 action。
- 同文件 79:严格 Origin/
X-User-Origin,仅已验证产品能转发用户 Origin;兄弟域不是天然可信。
公共 transport 应只有三种显式模式:浏览器会话调用、会话+产品服务身份的授权签发、product key+已签发委托的后台调用。不能一个 fetch wrapper 自动把 Cookie、Origin、Authorization 和所有服务凭据同时转发。
3. 后台执行授权(EXA)
签发入口 /api/platform/v1/execution-authorizations 需 product model:invoke、当前 session、合法 Origin:
EXA 持久绑定用户、product、product key ID、task_reference,默认 7 天;相同 tuple 返回原授权,不续期、不代表模型请求去重(同文件 21–59)。它冻结签发时产品角色集;若原先有角色而现在一个都不保留则拒绝;原先没有角色并不自动拒绝一般模型授权。这是执行授权,不是项目权限证明。
后台 /internal/relay/* 使用 product key + EXA;中间件拒绝 Cookie、Origin、Authorization。校验后删掉两种服务授权头,避免传给供应商:
过期/撤销 EXA 拒绝新派发;GET/HEAD 允许恢复原任务,但用户须启用、产品 Key 仍有效、原绑定角色约束仍满足:service/platform_execution_authorization.go:64。release 不退款,不取消已发送任务。模型授权和业务“停止”需要分别处理。
4. 材料授权(mat1)不能和 EXA 混成一种 Token
- service/platform_asset_authorization.go:44:mat1 仅用于材料,绑定用户、product/key、session ID、session/auth version 和过期时间,不能调用模型/钱包。
- 同文件 62–85:每次核验原 session/current version;退出或失效不能静默继续使用。
- middleware/platform_material_authorization.go:11:材料入口接受 mat1 或 EXA,禁止二者同时给。
- router/platform-router.go:35:浏览器 materials 与 worker internal/materials 两条入口。
适合抽离:鉴权头白名单、cookie 选择、origin 验证、issue/release、错误分类、凭据脱敏。不能抽离成允许调用方填任意 user_id 的“万能内部请求”。
生成、恢复与 Runtime
Platform 浏览器 /pg/* 与内部 /internal/relay/* 共用原生 handlers:router/platform-session-relay.go:11–75。消费者可以选 native 协议,但不应自己复制供应重试、结算或钱包。
主线非流式文本原请求恢复:
- service/platform_execution_text.go:19:
X-Platform-Text-Request-ID、oceanway.text-request.v1。 - 同文件 59:读取验证 user/product/EXA/request ID 全部原绑定;74 行明确 read 不重新 admission/扣费/调用模型。
- 同文件 89:在计费和 dispatch 前做 PG advisory lock,原 ID + protocol/body fingerprint;重复只回原任务,body 改动 conflict。
- controller/platform_execution_text.go:40:完整非流式请求到达后,客户端断线不取消后台原执行。
- router/platform-session-relay.go:71:GET
/internal/relay/text-requests/:request_id。
媒体原任务:同文件 32–36 的 task/artifacts/content;72 行原件 manifest /tasks/:task_id/artifacts/:artifact_key/original。原件读取必须沿原任务身份,不重新生成。
Runtime 已有适合共用的状态机、原派发存根、保存/交付与恢复:
- packages/platform-relay/src/client.ts:5:POST 最多一次,未知结果 ambiguous,读取有界重试。
- 同文件 278:统一 EXA 签发 client,先获得当前会话/Origin,再要求宿主持久引用。
- packages/platform-relay/src/store.ts:3:按原 execution 保存授权引用、fingerprint、task ID、outcome。
- packages/service/src/ports.ts:32:ServiceAuthenticator 必须先处理身份、对象和动作授权,RuntimeScope 只是隔离键。
- 同文件 50、64、77:Policy/Workflow authorizer、Planner dispatch/recover 等 host ports。
但是 Runtime SDK 未跟进最新契约:
- packages/platform-relay/src/contracts.ts:16 固定 Platform 0.15.0 / execution 1.1.0。
- packages/platform-relay/src/client.ts:374 的 submit 无 TextRequestID 字段,只有旧
oceanway.async-originals.v1,399 行拒绝其他 originalsVersion。 - docs/platform-contract-sources.json:52 只记录 task/artifacts/content,未包含新文本恢复能力。
- 工作树
runtime-owned-workflow/packages/server/src/execution-authorization.ts:39在实现公共授权 store,已有 authorize/forDispatch/forRecovery/release;该文件仍 untracked。不能把候选当发布,也不应各产品另起同类实现。
建议先给 Platform transport 做独立、窄、可版本化的 TS/Go 客户端;Runtime 使用它,非 Runtime 的产品也可使用它。Runtime 本身不是所有产品接入 Platform 的必经层。当前 Go Drama 也不必为了复用 TS SDK 被强迫重写后端。
统一素材和桶存储的现状
统一素材新源码为 temp-media-gateway(以下未注明版本的 Media 文件均在该根、HEAD 7bf5cc1)。Platform实际配置的统一素材目标为 https://media.oceanway.tech;pic-vps已观察到9220708统一素材部署实例和统一桶,公共status匹配OceanWay Media,精确反代映射未直接核验。另一主机仍存在7099bc2旧FileOwner实例。旧独立oceanway-media-gateway的三桶文档是另一历史链路。
当前职责分配是合理的:
- Platform:认证真实账号、有效订阅对应 storage entitlement。
- Media:唯一物理原件 writer、资产/版本、同账号字节去重、容量 used/reserved、引用绑定与删除。
- 产品:项目/节点/剧集等业务对象,素材引用和采纳语义,可靠同步 outbox。
- TOS:私有 object bytes;浏览器只获取短期读取能力。
证据:
- service/unified_assets.go:32:唯一统一桶
oceanway-media-assets-cn。 - 同文件 55:环境必须配置对应桶和签名 key,否则 fail closed。
- 同文件 76:Platform 签名同时绑定 account/app/method/path/过期和 entitlement,app header 本身不授权。
- Platform service/platform_assets.go:35:签名 2 分钟并计算 storage entitlement;69 行重建 outgoing 请求,只转 Content-Type 和 upload intent,不转输入凭据和 owner ID。
- Platform service/platform_asset_storage.go:13:默认 20 GiB;19 行只叠加生效且已交付的个人订阅,不把团队账单误计入私人容量。
- Media service/unified_assets.go:146:上传和生成唯一 Save 入口;199 行 physical file ID 按 owner+hash+bytes+MIME;同账号去重,跨账号不共用身份。
- 同文件 222:原 intent 找已写对象恢复丢失 receipt,234 行 conditional put + TOS forbid overwrite;262 行要求桶从未启用版本化。
- service/unified_asset_quota.go:36:UNKNOWN、缺任务不能释放预留;已成功视频要等实际归档。
跨产品引用已实现:
- service/unified_assets.go:482:pending binding 先保护文件,产品提交业务事务/outbox 后 confirm;同 command 的参数变化或已 released 禁止复活。
- 同文件 517:确认/释放按 owner+target_app 核对,只改变引用,不删除原件。
- 7bf源码同文件548的读取URL/read_until租约为10分钟;9220708部署实例对应源码已改24小时,并经Media public read proxy读取,见末节差异。业务侧存asset/version,不能持久签名URL。
- model/unified_asset_delete.go:12:purging 是持久删除 outbox;33 行检查 pending/active bindings;51 行检查其他 asset version;57 行检查 ingest 和读租约;确认对象不存在后才扣 used bytes。
- service/unified_asset_delete.go:72:维护 worker 重新执行 reservation、ingest、delete 恢复,不重新发模型。
目前数据面并非完全直传:产品→Platform materials→Media uploads→TOS 的上传路径让 Platform代理大体积body(controller/platform_assets.go:57允许512MiB;service/platform_assets.go:83流式转发)。Platform可以307到签名读取URL;9220708的URL落在Media public read proxy,再由Media取TOS字节,不是浏览器直连TOS。建议第一阶段复用现有路径;后续独立优化upload session/direct upload,仍由Media验证封存与配额。
最明显的版本冲突:旧 FileOwner 与新 assets 并存
- Media 已观察运行实例 7099bc2(不代表公共域名) 的
router/main.go:15–20挂SetFileReferenceRouter;router/file_reference.go:13–23提供/internal/files/v1,不存在 unified_asset 源文件。可用本地git show 7099bc2:router/main.go复核。 - Media 新源码 7bf5cc1 的
router/main.go:16–21只挂SetUnifiedAssetsRouter,不挂SetFileReferenceRouter。 - Media 新源码
docs/unified-account-assets.md:9宣称/internal/files/v1不再作为生产入口;这是该源码的目标路由,并非当前部署事实。 - Runtime packages/server/src/file-reference-client.ts:156 仍固定该旧入口,161–164 使用 Bearer+File Principal+File Grant。
- Runtime packages/server/src/file-reference-ports.ts:13、33 的生命周期是 claim_ref/access_grant + retain/renew/release。
- Platform service/native_task_originals.go:15 已以
oceanway.assets.v1为新协议,117–141 返回 owner_id + asset/version/file 元数据,保留 legacy 分支用于旧任务。
Runtime 与旧 FileOwner 实例可以按旧协议接线,是否实际这样接线需看配置;不能据新源码路由下结论说当前运行必坏。若把仍有旧SDK的消费者直接改接新assets实例,则旧调用路径不存在,必须作为联动接入的阻断项。这些不是把方法名改一下就兼容:旧 claim 与新 pending/active binding 的持久身份、释放证明、account-wide 跨产品共享都不同。应选择新 assets 契约为当前产品目标,提供统一 adapter,明确旧 Runtime 资产引用支持的版本;保留旧任务自己的 Writer/恢复链,避免“兼容”掩盖已退役接口。对现有活跃旧任务应维持原 Writer 和已承诺的恢复路径;新产品确定使用新 assets 后,完成消费者和服务联合验收再切换,不能为了测试绿无条件恢复旧入口,更不能未经迁移就删除仍被活跃 Writer 使用的入口。
Drama 与新 Studio 的实际接入缺口
- Platform controller/platform_assets.go:48 的 internal projects writer 只允许 studio/commerce。
- Media
service/unified_asset_projects.go:22–31project list 限定 console/studio/commerce。 - 同文件 71–80 固定 Studio
/canvas/{id}、Commerce/projects/{id};Drama 无 path。新 Studio 如果项目 URL/结构变化也必须明确修订,不应伪装旧 canvas。
所以要为 Drama/新 Studio 明确 product project projection 契约(真实项目 ID、title、relative product path、revision、deleted tombstone、asset/version members),由产品 owner 实现 outbox;Media 只维护投影与引用,不能自己创造产品项目。
可复用模块建议(按职责,而非统一大仓)
| 模块 | 服务/包落点 | 应包含 | 不应包含 |
|---|---|---|---|
| identity client | Platform 生产方生成类型 + TS/Go 薄客户端 | identity DTO、session错误、origin、return URL、操作者 action check | 本地项目 owner 自动赋值、自建密码/会话权威 |
| platform server transport | Platform client/server-only | 头白名单、超时/错误分类、EXA issue/release、原请求 ID、原任务恢复、无自动 POST 重试 | provider keys、供应选路、钱包计算、默认 root |
| assets client | Media contract + 经 Platform 受权 facade | upload intent/查询、asset/version、pending-bind/confirm/release、project projection、download、quota view | 每产品独立 S3 keys/新配额表、signed URL 长期存储 |
| runtime orchestration | 既有 Runtime | Job/Attempt/lease/fence/unknown、dispatch vs recover、Artifact/ResultSink | 平台身份权威、供应商计费、产品内容权限 |
| product operations adapters | 各产品管理 API | operator delegation验证、具体对象/动作、revision、审计、幂等 command | Admin 直接写各业务数据库 |
| contract acceptance fixtures | 生产方 + 最小消费者 CI | 版本与 endpoint、标准 fixture、跨账号拒绝、原单恢复、引用删除竞争 | 另建全局 Contracts 仓/巨大运行时依赖 |
不建议现在抽离所有服务端通用 helpers,也不建议把所有业务 orchestration 合并进 Platform。先稳定跨仓权限与状态边界,再移动重复代码;否则只是把不一致包装进一个 common 包。
建议实施顺序与验收
- 先建立一张真实版本/契约矩阵:服务运行 SHA、生产方契约 SHA、客户端版本、host writer 范围,明确 main/candidate/live。文档里“Drama 暂缓”“旧三桶”“file owner claim”“统一 assets”分别标记有效期。
- 统一身份和内部请求:冻结 principal/action/产品凭据/EXA/mat1 的责任;Go/TS 使用相同契约 fixture。验收 identity 成功但无 operator 权限仍被管理写接口拒绝,普通账号不能跨账号/项目读取。
- 先补当前统一 assets adapter:切掉新产品对物理桶/本地永久原件的独立权威,支持业务 pending binding→commit/outbox→confirm;Drama/new Studio 项目投影正式进入契约。验收同账号跨产品同原件,无额外字节配额;跨账号404;引用未释放时不能永久删除。
- 把原请求恢复带进公共 transport:部署/消费文本 request ID 能力必须配套;媒体维持原 task ID。验收客户端断线、worker重启、丢receipt只查询原单;保存失败不重生成;失效 EXA 不允许新调用但可恢复原单。
- 运营后台采用聚合 UI + 产品管理 API:统一登录/动作矩阵/审计字段,产品拥有自己的业务写入。管理表单可统一,不能让 Admin 掌握所有产品库密码。
- 最后整理 Runtime 引用与候选授权 Store:先判断现有 dirty候选的归属和基线,把 EXA生命周期集中到一处;新统一 assets 与旧 claim adapter明确分代。共享 SDK 更新后再移除各产品重复封装。
必要验证围绕边界,不是对每个 helper 写镜像测试:真实隔离 PG 并发/断线/重启、两账号两产品授权矩阵、TOS禁止覆盖与删除确认、消费端固定契约兼容。纯只读复盘本轮未运行测试,也未以测试文件存在当作本次通过。
补充:已观察的旧 FileOwner 实例(7099bc2),不是公共媒体目标的充分证据
主审以只读 SSH docker inspect 读取实际 image revision label,而非容器名:某主机仍有7099bc2旧FileOwner实例;Platform=ecac00e;旧Studio容器名含38028fe但真实image label=90eba1a。容器名不能用于判版本,running容器也不能直接用于判断公共域名路由。Platform 的 OCEANWAY_MEDIA_ASSETS_ORIGIN 指向 https://media.oceanway.tech;该目标可能属于另一主机/服务。此前10/26线上审计已有真实assets响应,故本轮不能说统一assets未部署。
7099bc2 的 service/file_reference.go:28–38 定义 FilePrincipal(principal/token/namespace/sourceUserID/sourceProject/canAdopt/canUpload/uploadProducts);71–120 从显式 FILE_BRIDGE 配置构建服务,permanent bucket 必须等于 ASSET_LIBRARY_BUCKET,若与 S3_BUCKET 共用需 MEDIA_RETENTION_MODE=permanent。123 行校验专用 Bearer + principal;grant TTL 为15分钟(26行)。这是旧FileOwner实例对应源码的事实,不是新统一素材服务配置事实。本轮未读取秘密、未验证该实例实际桶名或生命周期。
运行矩阵至少分为:旧独立media-gateway(历史三桶)、已观察旧new-api FileOwner(7099bc2,旧claim API)、新统一素材源码(7bf5cc1,assets API,20GiB账户配额)、公共media.oceanway.tech(实际服务制品/路由待核)。每项列producer SHA、入口、存储配置、消费者、writer/恢复owner、真实域名路由。7099bc2与新assets不同,不能单凭这个差异断言当前生产错配;确定的工程风险是同名Media覆盖不同协议代际,源码/部署/配置未形成一个可核对的兼容矩阵。
追加:9220708 统一素材部署实例和准确读取数据面
主审后续只读证据:pic-vps 的 oceanway-media-isolated-app image revision为 9220708b503778fd61af4309f3c5d5deb7186e3b,S3_BUCKET为 oceanway-media-assets-cn;公共 https://media.oceanway.tech/api/status 的server_address为该域名、system_name为OceanWay Media。由于宿主nginx -T未给出路由映射,本轮表述为“与公共目标一致的统一素材部署实例存在”,不是已直接证明每个URL均路由该实例。7099bc旧FileOwner是另一实例。
本轮已用git show核9220708源码(2026-10-26 fix(media): keep account identifiers opaque in public read grants),未切工作树、未部署。相对7bf5cc1共有20文件增量,主要是public read grant和测试。保存了无秘密源码快照供定位:
- router/main.go:16:挂统一assets router,不挂旧file-reference router。
- router/unified_assets.go:8:增加
/media/asset-references/:authorization/:filenameGET/HEAD/OPTIONS,写方法405。内部assets控制面维持。 - service/unified_assets.go:35:为异步供应排队读取,download TTL与删除保护租约改为24小时。
- service/unified_asset_read.go:28:public读取路径;35–42 capability含opaque owner_key、file_id、object-key hash、过期、文件名/下载策略。62–75独立domain HMAC签名,不暴露数值账号ID。
- 同快照80–106:限制GET/HEAD,验证签名、过期、原件ready/read_until和原object hash;108只允许单一Range;123–153由Media server取TOS HEAD/GET并转发字节。授权URL本身是bearer capability,不是新身份会话,也不能改作Platform资产控制授权。
准确数据面:浏览器/供应商→Media public capability URL→TOS(Media转流);上传仍产品/浏览器→Platform materials proxy→Media→TOS。控制面:Platform核账号/产品并签两分钟请求授权→Media保存/引用/配额;数据面capability为24小时,并配套删除租约。优化数据路径时应基于这一实现评估网络负担,不要把7bf的TOS presigned方案当作已部署922版本。
Platform运行态最终限定:线上image label虽为ecac00e,实际binary包含恢复实现字符串;无凭据GET /internal/relay/text-requests/architecture-readonly-nonexistent 返回401 JSON PLATFORM_PRODUCT_REQUIRED,假路由返回200 HTML SPA,确认文本恢复路由已挂载。binary SHA256为4d4068f5dd49e4c84344964cc741a42d923b27b68bd103a05abeb08377b10834。未持授权验证原任务恢复,不能声称端到端恢复通过,但绝不能说线上缺少端点。问题是制品来源元数据漂移。