2026-09-23·by Sijie Wang#standmeet#architecture#design

confusables

易混术语——形似而实异的术语

上级:architecture

本系统中容易混淆的词汇冲突,逐一精确拆分。文档里出现这些词却没加限定时,来这里对照。

1. 两个 MCP 平面

术语我们的角色是什么认证
capability plane(能力平面)MCP host(宿主)我们 agent 的工具:mcp-servers/ 下的 stdio 子进程 + owner 挂载的 ext-mcp,经由 mcpclient/capreg无——进程内本地(capsocket
service handle(服务端点,即 as-MCP)MCP server(服务端)对外的 /mcp/* facade(as-mcp-facade):owner 自己的 AI 推送 corpus(thesis 循环),别人的 agent 来读Sigv1

同一个协议,方向相反:在 service handle 上,箭头指我们(我们提供服务);在 capability plane 上,箭头从我们的 agent 发出(我们既是宿主也是消费者)。

规则:工程文档里不要单独说"MCP"——要说capability planeservice handle。(设计文档顺带提到的第三方 MCP server——比如 job-loop 的 Playwright MCP,是owner 自己的 Claude在消费——完全在我们的边界之外,两个平面都不算。)

2. 两条 plugin 轴线(而 connector 不是 MCP)

  • MCP capability pluginsmcp-capability-plugins)——我们 agent 的工具;讲 MCP 线协议;manifest + Origin 信任分级。
  • Connector pluginsconnector-plugins)——带凭据的外部集成(日历/邮件/……);讲的是contract(契约)CalendarProxy),不是 MCP;调用方拿到的是一个调用句柄,永远拿不到凭据本身。一个 capability 可以Require一个 connector(connector-deps)——这条依赖边是两条轴线唯一的交汇处。

3. Connector:action 模式 vs sync 模式

同一个 Hub,两个方向:action = 会话期间由代理对外发起调用(订会议、发邮件);sync = 在整理期把数据摄入进来(Obsidian vault sync 的归宿)。一个"已安装的 connector"本身告诉不了你是哪一种,得看它的 mode。

4. ext-mcp vs mcp-servers/

两者都活在capability plane上;差别只在Originmcp-servers/ 是内建的(随仓库一起发布,启动时加载),ext-mcp 是owner 注册的第三方 server。同一个协议,不同的信任分级(mcp-capability-plugins)。

5. Skill vs capability

capability 是 agent 可以调用的一个工具。skill 是一个被创作出来的产物(管理方式类似 prompt:library、CRUD、挂到 role 上),渲染为 SKILL.md,通过三级渐进展开skills-progressive-disclosure)暴露出来——它是搭在 capability(skill_useskill_run_script)之上的,本身并不是一个 capability。

6. writings 数据域 vs corpus 三层

两个独立的数据域,看上去都像"the content"——自 2026-07-09 起两者都住在同一张 corpus_notes 表里,靠 genre 列区分(backend/db/schema.sql):

  • corpus = genreraw → wiki → output(+ subjectivity)+ note_refs 边表(由 wiki_refs 改名)(three-tier-corpus-promotion);
  • writings = genre='writing' + writing_refs——独立的长文章,自己的 ref 重建流程。 vault sync(writings-import-export)过去只碰 writings;自 SyncVault 起它把每个顶层文件夹路由到一个 genre——wiki / subjectivity / raw / writing(backend/internal/corpus/obsidian/sync.go:2sync_classify.go:64);这个 wiki 名字里的"wiki",和 corpus 那一层的"wiki",也不是一回事。

7. Setup token vs owner keypair

Setup token = 首次运行对实例的认领(启动时打印出来,sha256 写进 instance_settings,用一次就消耗掉)。Keypair = service handle 的长期 Sigv1 认证,之后通过 admin API 创建。Bootstrap 对 operation——两条互不相关的生命周期(owner-keypair-auth)。

8. Access code = invitation(刻意合而为一)

这一条不是要拆开的易混项,而是要合并的:job-loop 设计把它们统一了——只有一张 access_codes 表,没有并行的"Invitation"概念。你在任何地方看到"invitation",它就是 access code(acl-and-quota-granularity)。

9. Frozen vs live(ACL 的时机分野)

Global capability 设置是live(实时)的(一翻转 → 正在跑的 session 就死)。Role 和 code 这两层是在签发时冻结(frozen at issue)进 RoleSnapshot 里的。"owner 改了 X,为什么 visitor 看到的还是旧规则?"——因为那一层是冻结的;"为什么 session 瞬间就死了?"——因为那一层不是(role-snapshot-frozenacl-and-quota-granularity)。

10. corpus.search vs corpus_search —— 差一个点和一个下划线,背后是两个后端

corpus.search(点号)是 owner/admin 那个 op,挂在 /api/admin/corpus/{genre}/search 后面。它调 repo.Search → Postgres 的 SearchNotes永远不碰 Meilicorpus_search(下划线)是访客 agent 的工具,走语料 lister,配了 Meili 就用 Meili,没配才退回 Postgres 全文。

这个坑是真花时间的:给线上挂上词法索引之后,在 admin 面上验证,得到的结果跟修之前逐字相同 —— 读起来就是"这次改动没起作用"。在其中一条上量检索改动,说明不了另一条的任何事corpus-retrieval)。

11. authoritative vs partial 导入 —— 同一个端点,相反的删除语义

POST /api/admin/obsidian/import 带一个 SyncMode。它的零值是 partial:只增改,什么都不删。authoritative 的意思是这次上传就是整个 vault,于是任何"由 vault 导入过、而这一批里没有"的东西都会被删掉 —— owner 的目录选择器发的正是这一种。

这个标记是一个普通表单值,所以它是因为漏传而丢失,不是因为报错而丢失,一次全量同步于是无声地退化成"只增不删"。反方向的错误更狠:把一次九个文件的局部上传当成 authoritative 发出去,会把另外一千条 prune 掉。

12. publish(vault) vs published(corpus) vs show_as_source(检索)

三个近义词,分属三个层。publish: true 是 owner 在自己 vault 里写的 frontmatter。published 是它映射到的语料列,而它只闸住公开的 reader 页面检索不看它 —— 一条语料可以对持码访客可检索,同时在公网上不可见,而这正是"码"存在的全部意义。show_as_source 又是另一回事:这条笔记能不能在答案里被引用

所以"这条笔记公开吗"其实是三个问题;而 vault 自己的 frontmatter schema 有好几个月对这三个一个都不认识 —— publish 不在它的白名单里,于是每一次加它的提交都被挡下来。