UI—MCP 对等:UI 能做的,handle 都能做
状态:已构建。 机制是
internal/infra/facadeparity—— 每个域把自己的 op 声明成数据(fp.Op:id、说明、入参 schema、种类、可达面),每一个面都是这一份注册表的投影(convergence-inbound-and-outbound)。由paritymanifest加一条棘轮强制。它暴露出来的 owner-MCP↔admin 缺口是真的,而且比估的大 —— 56 条,不是猜的那 ~15 条 —— 已经 56→0 还清。2026-09-07 于 36789537d 复核:paritymanifest.KnownMCPGaps()返回空表(gaps.go:17),棘轮(outward_test.go)在任何没有 MCP 孪生的新 admin 路由上都会变红;MCP 面是从 dispatcher 长出来的(routes/mcphandle/from_dispatcher.go:45),有意的不对称写成fp.Only(reason, facade)——keypairs.create/list/delete就是Only(FacadeAdmin),与下文的预测一致(manifest_table.go:41-49)。 在那之前(直到 2026-07),路线图把"MCP 与 HTTP 管理对等"列在外部化迁移之下,却没有任何强制机制——管理端 HTTP 接口和 service handle 的工具接口是两份手工维护的清单,二者之间的漂移是无声的。下面三个选项是促成这次构建的分析;②以fp.Op的形式落地(不是Command{}那个草图),①以棘轮 +Only(...)例外的形式落地。
想要的不变量
每一个能通过管理 UI 触达的 owner 操作,也必须能通过 service handle(StandMeet-as-MCP-server)触达——这样 owner 的 AI 会话就永远不会沦为浏览器的二等公民。例外必须是显式的,绝不能是意外产生的。
三种机制,强度递增
① 对等闸门(成本低——先构建这个)。 一个 CI 测试遍历 chi 管理路由表 × OwnerMCPBindings(),并将两者对照一张带例外清单的显式映射表进行检查;任何未被映射、又未被列入例外的管理端点都会让构建失败。和 check-connector-boundary(mechanical-guardrails)同属一类。例外清单本身就是审查材料——漂移要么被修复,要么被书面承认。合法的例外确实存在:密钥对创建(循环依赖——你需要一个密钥对才能调用 handle)、登录/认领(引导阶段)、上传形态的 UX。
② 声明一次,投影两次(结构性——真正的修复)。 漂移之所以存在,是因为有两份手写的接口。把每个 owner 操作只注册一次——Command{name, input schema, handler}——然后从同一份注册表中同时派生出 HTTP 路由和 MCP 工具。对等不再是一个需要被检查的属性,而变成在结构上不可违反。这正是平台自身的清单哲学(manifest philosophy)套用在了自己身上(OwnerMCPBindings 本来就已经是一份被遍历的声明;HTTP 那一侧只是还没有并进来),也是单一真相来源纪律(judgment-audit 维度 3:派生之物不应手写)的又一体现。
③ UI 反过来消费 handle(激进——目前不推荐)。 让管理 UI 本身成为 service handle 的一个客户端:这样对等在定义上就成立。这在哲学上与 entry-agnostic-agent("UI 只是另一个消费者")一致,但代价是实实在在的——内部调用要缴纳线协议(wire-protocol)税,session-cookie 与 Sigv1 之间要做桥接,上传/SSE 的形态也很难套进 MCP。机制②能在进程内拿到同样的保证,却不用付这份税。
建议
对所有新东西用②作规则,对遗留部分和例外用①作闸门。 ②从根本上消灭这一类漂移;①捕捉回归,并让例外清单保持诚实。只有当一个真正的第二 UI(IM 网关)让"UI 作为消费者"这件事本身变得举足轻重时,才值得重新考虑③。