插件端到端 owning 自己领域,host 核心去领域词¶
host 核心(qatlasd 中与插件无关的主干)不应携带任何单个插件的领域词或领域表。每个插件都要
端到端 own 自己的领域:自己的词表、自己的 PocketBase 集合(由插件自己的 Go package
注册迁移)、/api/<plugin_id>/* 下的 REST 路由、插件命名空间下的 hostapi 方法
(例如 lean.verifications.submit),以及自己的内存缓存。
为什么¶
早期接入(commits b79e622 + 160f806)把 lean-domain 制品直接放进了 host 核心:
internal/theorems/, internal/verifications/, internal/routes/theorems.go,
internal/routes/verifications.go,再加上 hostapi/core.go 把 theorems/get,
theorems/create, verifications/submit 暴露成通用 host 方法。这是领域泄露——host
不该知道 “theorem” 或 “verification” 是什么;这些是 lean 插件的概念。pages/get
(wiki domain)也是同一种泄露。
保留这种泄露会迫使每个新插件都切 host-core 代码,让插件抽取在不破坏 API 的情况下变得不可能, 也会阻止 external(三方)插件像 builtins 一样 own 自己的 schema。
移动什么¶
移入 theorems builtin 插件(
internal/theoremsplugin/或类似位置):git pull透传读取机制、
registry.json和 dependency graph 的内存缓存,以及/api/theorems/*路由。这个插件在本迭代中不 own 一个 PocketBase 集合 (见 ADR0004);已证明 Theorems 从 git 透传读取。
移入 wiki builtin 插件:
hostapi/core.go的pages/get(重新放到wiki.*namespace 下)。 现有internal/wiki/package 成为 wiki 插件的实现 package。本迭代完全移出代码树:
internal/theorems/,internal/routes/theorems.go,internal/verifications/,internal/routes/verifications.go,以及hostapi/core.go上的 lean-domain methods (theorems/get,theorems/create,verifications/submit)——理由见 ADR0004。保留在 host 核心:plugin registry/manifest/lifecycle、Paper catalog (
internal/papers/,paper_worksPG table——由每个插件共享)、auth/PAT、事件总线、 PocketBase,以及真正领域中立的 hostapi 方法(papers/getMarkdown,papers/getMeta,papers/getCitedRefs,events/publish)。
机制:一个 builtin-plugin 注册 hook¶
把 main.go 里临时拼出来的逐插件 RegisterTheorems(...), RegisterVerifications(...),
RegisterWiki(...), RegisterGraph(...), RegisterRAG(...) 调用,替换为每个 builtin 都实现的单一 hook:
type BuiltinPlugin interface {
Manifest() plugin.Manifest // matches plugins/<id>/plugin.json
RegisterMigrations(app core.App) error // own PocketBase collections
RegisterRoutes(se *core.ServeEvent, deps Deps) error // /api/<id>/*
RegisterHostAPI(r *hostapi.Registry) error // <id>.* methods (optional)
}
main.go 遍历 builtin list 并调用每个 hook。新的 builtin 插件只需加入这个 list——无需给 host 核心做手术。
可选能力:GitPullPlugin(lean + wiki)¶
git pull --ff-only 被所有透传读取上游 git 仓库的 builtins(wiki, lean)共享。我们把 wiki
package 当前的 pull/status helpers 抽取到一个 host-neutral 的 internal/gitpull/ package
(Pull(dir) (*PullResult, error), ReadGitInfo(dir) GitInfo, PullError, PullResult,
GitInfo——没有 wiki/lean 专属内容),并通过 builtin 可实现的可选子接口,把 pull 暴露成一种平台能力:
type GitPullPlugin interface {
GitRepoDir() string // working-tree path the host's `git pull --ff-only` runs in
OnPullSucceeded() error // plugin-specific post-pull work (wiki: cache.Refresh;
// lean: registryCache.Reload)
}
host-core 平台代码(也就是调用 BuiltinPlugin hooks 的同一个循环)对每个 builtin 做
GitPullPlugin type-assertion;满足接口的插件,平台会挂载一个统一形态:
POST /api/<id>/sync/pull + GET /api/<id>/sync/status,并保证两个路由在所有
pull-style 插件上行为一致。不需要 pull 的插件(graph, rag)不实现这个子接口;平台跳过它们。
为什么用子接口(而不是只做辅助 package)¶
两个选项都考虑过。纯 helper(每个插件自己的 RegisterRoutes 调用 gitpull.Pull)会把路由形态
和错误映射的一致性留给评审时人工把关。子接口把 “git-synced builtin” 提升为一等平台能力,
所以 host 能为每个自愿接入的插件保证一个 canonical /api/<id>/sync/* contract——想要同样行为的
external(socket/stdio)插件以后也可以自愿接入。成本只是一个很小的可选 Go interface;收益是为一种反复出现的形态统一 contract。
影响¶
如果/当 theorems 插件的 hostapi 方法(位于插件自己的 namespace 下,例如
theorems.*)增加时, external(socket/stdio)插件也可以写入这些方法——但不在本迭代。早期 commits 添加的 面向 push 的verifications集合被完全移除(见 ADR0004)。路由遵循逐插件 namespace:
POST /api/theorems/sync/pull(由GitPullPlugin挂载的统一形态)、GET /api/theorems/list,GET /api/wiki/pages等。hostapi/core.go收缩到真正由 host 共享的关注点。