Skip to content

[REQ-128][CODE] 宿主合同 v2:多组件 Bundle 图文法 + OAuth/Connection payload 形状 #749

Closed

Description

@jinjunnn

Covers

alpha-work#49 AC5 的结构前提:Phase 1 交付的 HostExtensionPackageV1 在格式上写死了
「一个 package 恰好一个组件」,Phase 2 的 Bundle 与 OAuth/Connection 前置结构上不可能在
该合同下表达。本票把宿主合同升到 v2。

为什么需要这张票(无主缺口)

Phase 1 剪裁把 #694 与 alpha-web#95 的 Bundle 半场砍掉后,没有任何一张票重新认领。
两仓全部 OPEN 的 REQ-128 票逐张查过:alpha-web 侧四张分别是 Phase 3(#96/#98)、
Phase 4(#99)、真实载荷(#108),无一覆盖。这是「砍范围没闭合用户可达路径」在
比 #732 高一层的复现。

Ground truth(2026-07-31 实读 @ 59211fe8)

位置 事实
alpha-package-envelope-v1.schema.json → components minItems: 1, maxItems: 1
同上 → components.items.dependencies maxItems: 0
decoder.ts:333 "envelope.components: Phase 1 requires exactly one component"
decoder.ts:227 入口是 decodeSingleComponent(...)
registry.ts:assertHostExtensionPackageRegistryV1() 硬断言锁死 4 profile + 1 capability
profiles/mcp-remote.v1.schema.json:50-54 + decoder.ts:552-554 auth 只允许 "none";无 connectionHandlerId
package-installability.ts:147 写死 header.envelope.components[0]

形状已预留:components 本就是数组、组件已带 required/dependencies、
decoder.ts:~258 已对 non-required 且不支持的组件返回 status:"skipped"。

Development plan

  1. 信封 schema:components.maxItems 1→16、dependencies.maxItems 0→15、新增必填 root。
  2. registry:增 maxComponents、maxMarkdownAssetBytes(清 #737 登记在案的 5 MiB 残留)
    与 alpha.mcp-oauth.v1/alpha.connection.v1 两个 token;同步 assertHostExtensionPackageRegistryV1()。
  3. 冻结 OAuth/Connection 的 payload 形状:auth 枚举扩为 ["none","oauth","connection"]、
    decoder.ts 同步、新增 connectionHandlerId 字段及其文法。只加 token 不够。
  4. decodeSingleComponent → decodeComponentGraph,flat 定义为四条:
    ①root 存在且 required === true;②root.dependencies 恰好等于全部 non-root id
    集合(无重复无遗漏无外部 id);③每个 non-root 的 dependencies 为空;④id 全局唯一。
    这四条蕴含无环 / 深度 1 / 无孤儿 / 无第二根。
  5. envelope.capabilities 改为全部组件的排序并集;derivePayloadCapabilitiesV1 增两分支。
  6. package-installability.ts 逐组件;safe view 增 leaf 列表与逐 leaf 原因码;
    保留 :157-161 的 non-required root 拒绝。
  7. binding 增 graphDigest(已批基线要求,Phase 1 单组件下未实现)。
  8. 重跑 generate-artifact.ts(artifact SHA 会移动,是预期)。

skipped 组件的三层语义(本票冻结)

面 是否含 skipped 组件
signed envelope capability union 含全部组件(发布方签名事实)
有效安装计划 / 授权集 / tx items 只含 supported 且未 skipped
V3 child mutation / claim set 只含 supported 且未 skipped

Acceptance and named gates

  • flat 图文法 ≥11 个负向:重复 id / root 不在表内 / root 非 required / root.deps 重复 /
    root.deps 漏列 non-root(孤儿)/ root.deps 含外部 id / non-root deps 非空(嵌套)/ 自指 /
    环 / 超 maxComponents / capability 并集不符。
  • skipped 三条语义闸:canonical「含一个已策展但宿主不支持的 optional child」的 Bundle,
    断言 union 仍含全部组件、该 child 零 fetch/零 tx item/零 claim/零 grant、
    preview 与 receipt 的 skip 原因逐字相同。
  • graph tamper + capability tamper 两个负向。
  • OAuth / Connection 各一正向、一未知字段负向、一非法 handler 文法负向、一 capability 派生向量。
  • 过渡门一:本票合并后旧 vendored producer 产物在新合同下应当被拒。
    package-installability.wiring.test.ts:24-42,63-121 改为断言「旧产物 → 明确拒绝 + 具名 reason code」。
    禁止在测试里手工给旧夹具补 root —— 那是假门。
  • req128-capability-matrix.test.ts 的新证据文件先进 delegates_to。
  • artifact 自闸绿。

Dependencies

无。Phase 2 的其余各票依赖本票。

Out of scope

cloud profile、nested Bundle、semver solver、managed Plugin ABI、alpha-web 侧改动(另票)。

Exit condition

Merged PR + 上列 named gates 全绿 + 合同 docs 同步。

Activity

  1. added
    type:featureNew user or system capability
    prio:P1High-value near-term delivery
    area:runtimeServices, jobs, infrastructure, or operations
    cross-repoRequires coordinated work in multiple repositories
    on Jul 31, 2026
  2. jinjunnn commented on Aug 1, 2026

    @jinjunnn
    OwnerAuthor

    ⚠️ 票面勘误(2026-07-31):Development plan 第 3 条写的是已被推翻的 rev2 设计

    本票正文第 3 条写「auth 枚举扩为 ["none","oauth","connection"]」。
    那是方案 rev2 的形态,已在方案审计 R2 被判 NOT-FIXED 并由 rev3 修订 B 取代。
    (R2 判据:只给枚举名与平级 connectionHandlerId,没有字段名、结构、条件必填关系与 handler 文法,
    发布端据此产不出唯一合同。)

    权威形态是 rev3 修订 B 的判别联合,PR #751 实现的就是它:

    "auth": {
      "oneOf": [
        { "const": "none" },
        { "type":"object", "required":["kind","prerequisiteId","required"],
          "properties": { "kind": {"const":"mcp-oauth"}, "prerequisiteId": {...}, "required": {...}, "label": {...} } },
        { "type":"object", "required":["kind","prerequisiteId","required","connectionHandlerId"],
          "properties": { "kind": {"const":"alpha-connection"}, ..., "connectionHandlerId": {"pattern":"^[a-z][a-z0-9-]{0,63}$"} } }
      ]
    }

    跨字段不变量五条归 decoder(含 kind==="mcp-oauth" 时 headersTemplate 不得含
    Authorization(大小写不敏感)
    —— token 注入归引擎,发布方自带模板即绕过 token store);
    capability 派生三条;mcp-local 本期不加 auth。

    这条勘误本身造成过真实代价:并发实现时有一个 agent 照票面直译写了 rev2 形态,
    与另一条按 rev3 实现的 lane 在同一分支上撞车。最终树已确认无 rev2 残留
    (符号轴 + 字面量轴 + schema 轴三条独立检索),旧拼法 auth:"oauth" 现在只出现在负向用例里。

  3. added 3 commits that reference this issue on Aug 1, 2026
  4. added 7 commits that reference this issue on Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:runtimeServices, jobs, infrastructure, or operationscross-repoRequires coordinated work in multiple repositoriesprio:P1High-value near-term deliverytype:featureNew user or system capability

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions