两个收口——出站与入站
上级:structure
后端最深的那个结构性想法,而它一直没有笔记。一个能力能做什么、以及它能反过来向宿主要什么,各自只从一个地方过——而且两者都由闸门守着,不靠评审。
出站:dispatcher
每个域把自己会做的事声明成数据(fp.Op —— id、说明、入参 schema、种类、可达面)。dispatcher 把这些声明汇成唯一一份注册表;每一个对外的面 —— admin HTTP、owner MCP、API-key 面、访客 agent 的工具 —— 都是这一份注册表的投影,而不是它旁边手写的另一个网关。
check-routes-via-dispatcher 守着这条线:一个面直接够到域门面就是红。它以棘轮方式运行——还没迁完的文件有一份基线,只许变少。
为什么要紧:四个手写网关,正是一个产品最后长出"这个 op 在 admin 面板上有、在 MCP 上没有"的方式。parity 于是不再是一件要去审计的事,而是一件做不到的事(facade-parity、ui-mcp-parity)。
入站:desk
沙箱里的能力会反过来够回宿主(读语料、写自己的存储、查配额)。这条反向的路收口在 internal/routes/hostdesk,两条结构规矩把它钉在那儿:
- 只有 desk 能开能力的 socket。
capsocket.ListenWith只允许出现在 hostdesk(生产)和 agentcore(eval 的小宿主,用 stdio 提供同一批域声明的 op)。出现在别处——尤其是组装根——意味着某个能力拿到了一个 desk 的清单里没有的 socket,于是"沙箱能向宿主要什么"这个问题不再有答案。 - 只有域能声明一个 host op。
hostop.Op{字面量住在internal/<域>/{ops,usecase}/,或者两根轴自己的路由包里。组装根负责接线,它不铸造动词。
两者互为镜像:dispatcher 回答"宿主能替外面做什么",desk 回答"沙箱能向宿主要什么"。对称本身就是要点——一条绕过 desk 的入站够回,跟一个绕过 dispatcher 的出站面,隐形程度完全一样。
内核不持有任何能力
check-core-agnostic 是一条字符串棘轮,它存在是因为 go-arch-lint 有个盲区:它只看包与包之间的 import 箭头,所以看不见"一个内核文件把订会逻辑写在了自己包里"——那种文件的每一根箭头都是绿的。
基线已排干,闸门跑在纯红模式,一条豁免都没有。最后被清掉的那一条值得当范例留着:agent_instruction.go 里出现了 calendar 这个词,因为那段常驻的日期时间上下文对每一个访客说"owner 的日程跑在这个时区"、并让他在提议时间前先确认自己的时区——一条排期指示,发给了手上根本没有订会工具的访客。现在内核只陈述事实(现在几点、哪个时区、访客时区已知时是哪个);怎么换算、什么时候反问、要不要两边都报,是订会那个能力自己的事,写在它自己的 MCP 说明书里,授了才出现。这条规矩压成一句:内核陈述事实,能力下达指示。
向内那一侧只封,不解封
一份凭据只走到半路:向内这一侧,owner 填完表,它被封存起来,而这一侧完全没有打开它的办法。打开发生在出站那一侧,由它把明文交给要花掉它的人。封/开这一对不是某种连接器——它是两者共同站着的那个底层机制。
check-core-seals-only 用两个范围守它,因为这条不变量有两个逃逸口,而只有一个是看得见的。import 级的检查抓得住"向内的包 import 了解封器",但它抓不住一个类型是 func([]byte) ([]byte, error) 的结构体字段从外面递进来——那玩意儿一个非法包都没 import,go-arch-lint 看到的是一张全绿的图。所以内核被禁掉的是解封的词汇,不只是那条 import。
一个调度器,以及"轴用数据声明"
check-periodic-via-scheduler—— 任何按时跑的东西,都走那唯一一个调度器。语料 reconcile 那个循环的手写版本从来没在任何地方登记过:它一直在跑,而 Monitor 的后台任务面板上看不见它。一个没人数得出来的定时器,是一个没人能被告知的进程。check-axes-declare-in-data—— 两根插件轴把内建件声明成数据,放在各自的顶层目录(backend/capabilities/<id>/manifest.yaml、backend/connectors/<id>/manifest.yaml),组装根只负责拼装。它们以前是cmd/server里的 Go 字面量:一个能力的身份、它要用哪些 host op、它占邀请码上的哪个字段、它的配置默认值——全写在程序被接线的地方,而不是这个能力被描述的地方。加一个能力意味着改组装根,而组装根身上长出了每个能力的形状的一份拷贝。
共同的形状
这五条规矩是同一个动作:事实只放在一个地方,其余一切都是它的投影,再由一道机械闸门让第二份拷贝不可能存在,而不是"不建议存在"(mechanical-guardrails)。它们防的不是 bug,是同一件事的两份描述之间的漂移——而评审对这种漂移一贯抓不住,因为每一份拷贝单独看都是对的。