文档
历史档案文档OceanWay 架构架构决策记录

历史 · ADR-028:Contracts First 与 Core 准入纵切

重构前档案,仅供追溯,不作为新版本执行指令

历史档案 · 2026-09-11 重构前快照。 本文中的“当前”“已冻结”和实施顺序属于旧基线。新版本以现行总览实施计划为准。

属性内容
状态已采用,首个实现基线已通过独立 CI 验收
决策日期2026-09-03
适用范围oceanway-contractsoceanway-core 以及随后接入的 API Edge、Surface 与 Gateway
前置决策OW-ADR-006、011–015、019、022–027

背景

十四仓边界建立后,最大的风险不是仓库数量,而是各产品并行开发出不同的身份、模型、Run、资产和钱包语义。如果先迁页面、再补共享契约,Studio、Console、API Edge、Drama 和 Commerce 会各自形成临时事实源;后续即使 UI 看起来统一,调度、计费和追溯仍无法闭环。

因此下一阶段不以“先完成某个页面”为目标,而以一条可执行、可回滚、可诊断的最小业务纵切作为系统骨架。

决策

1. Contracts 必须先于运行仓发布

oceanway-contracts 是跨仓 wire contract 的唯一来源。运行仓只能依赖固定 Release 版本,不允许使用 Git 分支、本地相对路径、复制 TypeScript 文件或跨仓源码导入。

首发基线至少包含:

  • opaque/branded 稳定 ID;
  • Request Context、Tenant Context 和 Developer Access Context;
  • credits、entitlement 与真实 ISO money 的判别联合;
  • Asset Version 引用;
  • Model Offering 公共投影与 Model Execution Target 内部投影;
  • Agent Revision 与 MCP Grant 引用;
  • Run Admission、Execution Manifest 和 Run 事件;
  • Text/Media Gateway 的提交、观测、不可变 ProviderUsageEvidence / ProviderCostEvidence 引用与安全错误;
  • Canonical Event Envelope;
  • 由运行时 Schema 自动生成的 JSON Schema 制品。

所有 wire object 首版采用严格字段校验。因此给既有对象增加字段也按不兼容变更处理;兼容性扩展优先新增独立 Schema 或新的事件版本。不能一边拒绝未知字段,一边把“新增可选字段”声明为 minor 兼容。

1.1 Contracts 依赖必须绑定私有 Registry 与同一发布制品

  • GitHub Packages 中的 Contracts 包只向明确授权的消费仓开放;oceanway-core 的 GitHub Actions 获得 Read 权限。
  • Core 的首个历史基线使用 pnpm 的 gh: registry-qualified dependency 锁定 @oceanway-ai/contracts@0.1.0;后续受控 API 准入验收固定使用 @oceanway-ai/contracts@0.2.0。任何阶段都不能因 Registry 配置异常解析到同名公共包。
  • pnpm 的 minimumReleaseAge 例外只允许当前明确固定的 Contracts 精确版本,不对整个组织 Scope 或浮动版本放宽供应链门禁;0.1.0 是首个历史例外,0.2.0 是当前受控准入制品。
  • Contracts Release Workflow 先生成唯一 tgz,再用同一个文件发布 GitHub Package 和 GitHub Release;不得分别重建两个制品。
  • Contracts 新增制品比对 Workflow,按版本下载 Registry 与 Release tgz、校验摘要并递归比较解包内容。该 Workflow 是发布验收门禁;0.2.0 已由 Verify Run 33756418040 正式通过,不能据此倒推所有历史制品都已自动验证。

2. 模型公开面在导入边界隔离

webapiinternal 是发布目标,unpublished 是发布状态而不是第四个 Surface。公共 Model Offering 与内部 Model Execution Target 使用不同导出入口:

  • Site、Developer Center、Console 和产品 UI 只能导入公共模型目录契约;
  • Core 与 Gateway 可以导入内部执行目标契约;
  • codex-auto-review、规划模型、自动评测模型和 Provider 绑定没有对应公开 Offering 时,无法进入网页或公共 API 目录。

这项限制必须由包导出和 CI 验证,不能只依赖页面过滤。

3. Core 保持模块化单体

首期 Core 在一个仓库和一个 PostgreSQL 事务边界内实现以下模块:Identity、Tenancy、Authorization、Developer Access、Resource Registry、Asset、Execution、Metering、Billing、Agent、MCP、Model Control、Operations 与 Audit。

模块拥有各自的聚合、Repository、表和事件。Agent 只拥有 Agent Definition、Revision 与 Deployment;Run、Step、Attempt、Execution Manifest 和 Output 只由 Execution 拥有。Provider Credential Version、物理 Channel/Supply 和 Provider Task 保持 Gateway 私有。

Canvas Runtime 延后到 Phase 4;当前 Contracts/Core 基线不提前冻结 Canvas 节点协议。

4. 首个纵切采用 Run Admission

首个可执行纵切固定为 API Surface 的 Run Admission:

上述动作、幂等结果与 Outbox 必须在一个 PostgreSQL 事务中提交。projectId 可选,billingAccountId 必填并由服务端验证;首版只接受 credits,不能把积分伪装成货币,也不能把 credits、entitlement 和 money 相加。

Run 级 Execution Manifest 冻结创建时的 Actor、Execution Principal、租户、付款账户、认证上下文、授权决策、Offering Revision、initial Execution Target、Routing Policy Revision、Reservation、pricingSnapshotId、关联 ID 和数据分类。本文将它的语义角色称为 RunAdmissionManifest;已发布 Contracts 的 ExecutionManifest 已是 Run-level 基线,不能误塞 runStepIdexecutionAttemptId 或具体 Gateway 路由。Developer Access 链由准入事务校验,不在 Manifest 中复制另一份可变资源投影。Manifest 创建后不可修改;执行变化通过 Run/Step/Attempt、每次 Attempt 的独立 AttemptExecutionManifest 和事件表达。

Canonical Event Envelope 固定使用 aggregateId 与正整数 aggregateRevision,并携带 eventIdeventTypeschemaVersionoccurredAtproduceractorPrincipalId、Organization、Workspace、可选 Project、correlationId、可选 operationIdcausationIdtraceId 和 payload;其中 causationIdtraceId 按事实可选。不得恢复含义模糊的 subjectId 或缩写 orgId

5. 本纵切明确不执行外部副作用

当前基线只完成准入与预占,不调用 Text/Media Gateway、Provider、Agent、MCP 或 Asset 写入,也不开放客户写 API。这样可以先验证租户、授权、模型发布面、账务与幂等不变量,而不制造未知提交或重复生成。

实施快照

  • @oceanway-ai/contracts@0.1.0 已作为首个固定版本发布;包根只暴露公共安全契约,公共模型目录使用 public/model-catalog,执行、模型控制和网关契约使用 internal/* 子路径。
  • oceanway-core 已在 Commit 77f336a 形成 PostgreSQL Run Admission 功能基线,包含模块所有权清单、数据库迁移、单事务准入、数据库不变量与真实 PostgreSQL 集成测试;本地已通过 5 项单元测试、14 项专用 PostgreSQL 集成测试、类型检查、构建、依赖审计以及 /livez/readyz 启动验证。
  • Core 随后的 4d66b6c 已锁定私有 Contracts 依赖,并由 独立 CI Run 33745852471 通过格式、类型、单元测试、构建、专用 PostgreSQL 集成测试和生产依赖审计。
  • 上述 0.1.0 与 Core Commit 是 2026-09-03 的首个历史验收基线。后续受控 API 准入已固定到 @oceanway-ai/contracts@0.2.0(Commit ce323954;CI 33756169615;Release 33756329273;Verify 33756418040;tgz SHA-256 731b9a54d846a7fb8714ba651d41d466abfa2b2b98a4f1466eedb0287e0a23c4)、Core f9e55b6(CI 33777925718)和 API Edge f97cf5f(CI 33774539995)。
  • Infrastructure e72e5f3 已收录 Gate 9cc3c9c 产生的正式跨服务证据 controlled-admission-e2e-9cc3c9c49b16-f9e55b6e56e4-f97cf5f27027.json。该证据验证真实 Release tgz、HTTPS JWKS、RS256 Workload JWT、Edge/Core Socket HTTP 与隔离 PostgreSQL 下的默认关闭和受控准入链路。
  • 首个 Contracts-first/Core Run Admission 与后续 API Edge 受控接入据此均已验收;这不代表生产部署或公网开放,也不包含 Gateway 执行与输出、Outbox 发布、Metering 或 Settlement。

上述已发布 ExecutionManifest 与准入证据是 Organization-backed 的 Run 级历史基线,不能因目标文档引入 tenantKind / tenantIdmodelRoutingPolicyRevisionId、Attempt Manifest 或 Route Binding 而被追溯改写。目标字段必须进入新的固定 Contracts 版本并通过 Producer/Consumer 兼容门禁;Personal Space API Admission 在 tenant-aware Manifest、Run Event、Wallet Event 与授权门禁共同发布前保持禁用。

Writer 与迁移规则

在某类命令切换前,oceanway-vozeb 仍可以是旧事实 Owner。接入新 Core 时只允许两种模式:

  1. 旧入口代理到 Core,Core 是唯一 Writer;
  2. 旧实现继续写,Core 只做不产生事实和费用的 Shadow Read/校验。

禁止旧、新实现同时创建 Run、Reservation、Ledger Entry、Asset 或 Provider Task。回滚只改变后续新命令的路由;已经受理的 Operation 由原 Owner 处理到终态或进入 Reconciliation。

准入事务基线验证门禁

本决策的准入事务基线需要同时通过:

  • Contracts 的运行时校验、TypeScript Node/Web 消费测试、JSON Schema 漂移检查、打包检查和依赖审计;
  • 公共模型导出无法导入内部 Execution Target 的负向测试;
  • Core 模块聚合唯一所有权测试;
  • 专用 _test PostgreSQL 上的真实事务测试,且关闭文件级并行;
  • 并发同幂等键只产生一个 Run 和一份 Reservation;
  • 相同幂等键不同语义被拒绝;
  • 跨租户、无授权、余额不足或中途约束失败时没有部分写入;
  • Manifest 数据库级不可修改;
  • Run 读取受 Organization、Workspace 和可选 Project 限制;
  • Outbox 与业务事实在同一事务创建,并携带所需 Operation/Correlation/Trace 关联;Outbox Publisher 的外部发布、消费回执和运维读模型属于下一阶段;
  • 包、Tag、Changelog、Commit 和 CI 结果可追溯。

上述准入基线现已由 Contracts、Core、API Edge 独立 CI 和 Infrastructure 受控跨服务证据完成验收。完整 Request Attempt、Error Occurrence、事件发布与消费链路不由本 ADR 的已完成状态代替,当前由 Outbox Publisher 与 Ops Explorer 阶段继续实现。

后续顺序

本纵切完成后按下列顺序推进,不同时展开全部产品迁移:

  1. API Edge 适配(受控门禁已完成):终止 DeveloperCredential,构造受信 Request Context,调用 Core;API Edge 不保存第二份 Run、余额或模型事实。运行时仍默认禁用 Admission,尚未开放公网。
  2. Outbox Publisher 与 Ops Explorer(当前阶段):依照 ADR-030 以 PostgreSQL-first Dispatcher 可靠投递事务事件,建立 Operation/Run/Reservation 查询投影,为 Admin 的只读 Run Explorer 提供第一条真实数据链;当前仅完成文档基线,代码与验收待实施。
  3. Metering 与结算:令 Gateway 只追加不可变 ProviderUsageEvidence / ProviderCostEvidence 与 source ref,由 Metering 唯一创建规范 MeterEvent / ProviderCostFact、处理幂等/更正/对账;Billing 按版本化 Eligibility 和合格 MeterEvent 计算目标净额,只有 BillingFinalizationDecision 封闭完整 Attempt×Charge Dimension 集合后才结算或释放,未知/冲突进入对账,ProviderCostFact 不单独触发客户账务;Operational Observation 不能驱动结算。
  4. Text Gateway canary:使用固定 Gateway Contract 接通一条文本执行链;Media 按同级接口随后接入,不做同 Attempt 双投。
  5. Asset Output:将成功结果登记为 Asset Version 并保留 Run/Attempt/Blob lineage。
  6. Surface 迁移:先迁 Console /ai 的一个最小调用链,再迁 Studio;旧实现逐命令切换 Writer,始终禁止业务双写。

Canvas Runtime、完整 Agent/MCP 组合、Drama、Commerce 和 FDE 私有交付在上述链路通过后进入各自阶段。

影响

收益是所有平台从第一条调用开始就共享同一租户、付款方、模型发布面、Run 和追踪语义,且 Admin 能基于真实事件建设诊断能力。代价是首个可见页面功能会稍晚,但可以避免后续为多套钱包、模型目录和任务表做高风险合并。

On this page