外置就要彻底外置
上级:structure · 邻居:owner-facade-from-registry · mcp-capability-plugins · convergence-inbound-and-outbound
一个被外置的能力,必须连它自己的存储一起带走。 如果内核还攒着那张表,那这个能力只是换了个地址,不是被外置了 —— 而"更整洁的地址"能通过每一道闸门,同时什么都没改变。
它命名的那个失效模式
把一个能力搬出内核,很容易只搬一半,而这个一半的状态还很舒服:代码住进了 capabilities/<id>/,import 图是绿的,arch-lint 过了,diff 看起来像进展。留在原地的是数据 —— 共享 schema 里的一张表、共享数据模块里的一个 repo、共享配置结构体上的一个字段。内核仍然知道这个能力存在,而加下一个能力仍然要改中间那一层。
诊断的问题不是"代码住哪儿",而是 "把这个能力删掉,内核里还剩下什么?" 如果答案是一张表、一个列、一个结构体字段、或者一个 switch 分支,那它就不是外置的。
彻底外置长什么样
- 自己的存储。 每个能力有一份隔离存储,按它自己的声明 provision —— 绝不是一个"每个能力都伸手进去"的共享数据模块。隔离存储正是让出站收口(码上的那个字段)、入站够回(沙箱的读写)、用量闸三条路,对每个能力都从同一处取的原因。
- 自己的声明,形式是数据。 身份、它要用哪些 host op、它占邀请码上的哪个字段、它的配置默认值 —— 写在
backend/capabilities/<id>/manifest.yaml,而不是组装根里的 Go 字面量。写在这个能力被描述的地方,不是程序被接线的地方(convergence-inbound-and-outbound)。 - 自己的说明书。 策略和措辞跟着能力自己的 MCP
instructions走,于是一个没被授予它的会话根本读不到。内核陈述事实,能力下达指示。 - 它的边一起搬走。 让一次搬家烂掉的不是代码 —— 是错误表、lint 豁免、testid、
'use client'边界。这些都不会自动跟着走,而其中任何一个没跟上时不会报错;系统只是比原来少做了一件事。
为什么内核必须忘得掉
外置是否成立,检验在 check-core-agnostic 那条棘轮上:内核包里根本不允许出现任何一个具体能力的名字。 不是"不许 import",是不许被提到。import 图的检查看不见"一个内核文件把某个能力的逻辑写在了自己包里",因为每根箭头都是绿的。所以那道守卫读的是字符串,而且跑在空基线上:一条豁免都没有。
被它抓到的那个范例不是一张表,是一句话:内核那段常驻的日期时间上下文提到了 owner 的日程,于是把排期建议送给了手上根本没有订会工具的访客。能力早就外置了;关于它的一句话没有。