[REQ-128][CODE] 宿主合同 v2:多组件 Bundle 图文法 + OAuth/Connection payload 形状 #749
Copy link
Copy link
Closed
Labels
area:runtimeServices, jobs, infrastructure, or operationsServices, jobs, infrastructure, or operationscross-repoRequires coordinated work in multiple repositoriesRequires coordinated work in multiple repositoriesprio:P1High-value near-term deliveryHigh-value near-term deliverytype:featureNew user or system capabilityNew user or system capability
Description
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
- 信封 schema:
components.maxItems1→16、dependencies.maxItems0→15、新增必填root。 - registry:增
maxComponents、maxMarkdownAssetBytes(清#737登记在案的 5 MiB 残留)
与alpha.mcp-oauth.v1/alpha.connection.v1两个 token;同步assertHostExtensionPackageRegistryV1()。 - 冻结 OAuth/Connection 的 payload 形状:
auth枚举扩为["none","oauth","connection"]、
decoder.ts同步、新增connectionHandlerId字段及其文法。只加 token 不够。 decodeSingleComponent→decodeComponentGraph,flat 定义为四条:
①root存在且required === true;②root.dependencies恰好等于全部 non-root id
集合(无重复无遗漏无外部 id);③每个 non-root 的dependencies为空;④id 全局唯一。
这四条蕴含无环 / 深度 1 / 无孤儿 / 无第二根。envelope.capabilities改为全部组件的排序并集;derivePayloadCapabilitiesV1增两分支。package-installability.ts逐组件;safe view 增 leaf 列表与逐 leaf 原因码;
保留:157-161的 non-required root 拒绝。- binding 增
graphDigest(已批基线要求,Phase 1 单组件下未实现)。 - 重跑
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 同步。
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
area:runtimeServices, jobs, infrastructure, or operationsServices, jobs, infrastructure, or operationscross-repoRequires coordinated work in multiple repositoriesRequires coordinated work in multiple repositoriesprio:P1High-value near-term deliveryHigh-value near-term deliverytype:featureNew user or system capabilityNew user or system capability
Activity
jinjunnn commentedon Aug 1, 2026
本票正文第 3 条写「
auth枚举扩为["none","oauth","connection"]」。那是方案 rev2 的形态,已在方案审计 R2 被判 NOT-FIXED 并由 rev3 修订 B 取代。
(R2 判据:只给枚举名与平级
connectionHandlerId,没有字段名、结构、条件必填关系与 handler 文法,发布端据此产不出唯一合同。)
权威形态是 rev3 修订 B 的判别联合,PR #751 实现的就是它:
跨字段不变量五条归 decoder(含
kind==="mcp-oauth"时headersTemplate不得含Authorization(大小写不敏感) —— token 注入归引擎,发布方自带模板即绕过 token store);capability 派生三条;
mcp-local本期不加 auth。这条勘误本身造成过真实代价:并发实现时有一个 agent 照票面直译写了 rev2 形态,
与另一条按 rev3 实现的 lane 在同一分支上撞车。最终树已确认无 rev2 残留
(符号轴 + 字面量轴 + schema 轴三条独立检索),旧拼法
auth:"oauth"现在只出现在负向用例里。[#749][CODE] 审计修复:门二按签名事实判、graphDigest 立真闸、占位符规则归还 decoder
[#749][CODE] 合入主线并修集成红:#705 单组件夹具补上合同 v2 必填的 root
[#749][CODE] 宿主合同 v2:多组件 Bundle + OAuth/Connection 形状 (#751)
Merge origin/alpha into feat/704-alpha-connection
[#704][CODE] Alpha Connection handler、记录与 prerequisite 生命周期 (#755)
[#759][CODE] re-vendor alpha-web producer 产物,翻门一为正向并恢复 admission 真夹具 (#…
[#758][CODE] 账本图摘要改名 installedGraphDigest —— 与授权绑定的 graphDigest 分开 (#770
[#807][FIX] R1 四条:冒号文法收成精确二选一、plugin 补 strict 轴负例、界改成可移动、合同索引对齐
[#811][CODE] re-vendor producer artifact 到 aw@9fcd83d:closure 变五 prof…
[REQ-128][CODE] 宿主合同注册 opencode-plugin profile,并把 engine:config/engin…