在 #4777 建门禁时顺带发现,不在该 issue 范围内,按 Prime Directive #10 单独记录。
发现
scripts/check-init-service-contract.mjs(#4471 / ADR-0116 的声明覆盖门禁)只匹配一个 callee:
// scripts/check-init-service-contract.mjs
if (ts.isPropertyAccessExpression(callee) && callee.name.text === 'getService') {
而 kernel 的服务解析有两个入口 —— getService 和 getServiceAsync
(packages/core/src/kernel.ts:505)。两者的排序风险完全相同:插件 init() 的执行顺序
决定能不能解析到,ADR-0116 的 dependencies / optionalDependencies / requiresServices
对两者一视同仁地生效。但门禁只看得见前者。
这不是理论问题 —— #4772 正是这么溜过去的
AuthPlugin.init() 里(修复前,f2eb85007^):
cache = await (ctx as { getServiceAsync?: (n: string) => Promise< unknown > }).getServiceAsync?.('cache');
当前是否已经红?
否。今天 packages/** 里的 getServiceAsync 调用点(rest/src/rest-server.ts、
runtime/src/http-dispatcher.ts、runtime/src/dispatcher-plugin.ts)都在请求期路径上,
不在任何插件的 init() 里 —— 所以这是一个潜伏的洞,不是现存的红。
补上词表大概率仍然是绿的,应该顺手做掉。
建议
把 getServiceAsync(以及 hasService 之类真正读注册表的入口,如果确认存在)加进该脚本的
lookup 词表,并补一条 self-test:init() 里未声明的 getServiceAsync('X') 必须判红。
需要顺带核对 --list 的边名输出(现在硬编码写作 getService('X'))。
为什么不在 #4777 里一并做
#4777 建立的是另一条规则(「读注册表可以,记账不行」),两条门禁互补:
#4471 说「你得声明」,#4777 说「你没声明就不许记账」。 扩 #4471 的词表是它自己的
scope,而且改动会波及一条与本次派发不同的判定语义,单独一 PR 更干净。
发现于:PR #4833(#4777)。
在 #4777 建门禁时顺带发现,不在该 issue 范围内,按 Prime Directive #10 单独记录。
发现
scripts/check-init-service-contract.mjs(#4471 / ADR-0116 的声明覆盖门禁)只匹配一个 callee:而 kernel 的服务解析有两个入口 ——
getService和getServiceAsync(
packages/core/src/kernel.ts:505)。两者的排序风险完全相同:插件init()的执行顺序决定能不能解析到,ADR-0116 的
dependencies/optionalDependencies/requiresServices对两者一视同仁地生效。但门禁只看得见前者。
这不是理论问题 —— #4772 正是这么溜过去的
AuthPlugin.init()里(修复前,f2eb85007^):cache由CacheServicePlugin通过providesServices = ['cache']提供 —— 是一个workspace 提供的服务,正是该门禁的判定对象;
AuthPlugin声明里没有任何一条覆盖它(requiresServices = ['data', 'manifest'],依赖里也没有
com.objectstack.service.cache);getServiceAsync而完全不可见。代价见 bug(plugin-auth):
[auth] no cache service registered在 CacheServicePlugin 注册前 21ms 就喊了 —— 误报,且把人引向「你需要 Redis」 #4772:showcase 冷启里 21ms 的顺序差把undefined冻进了 better-auth 配置,多节点部署的限流计数永远到不了共享存储(ADR-0069 D2 宣称了运行时没交付的能力)。
当前是否已经红?
否。今天
packages/**里的getServiceAsync调用点(rest/src/rest-server.ts、runtime/src/http-dispatcher.ts、runtime/src/dispatcher-plugin.ts)都在请求期路径上,不在任何插件的
init()里 —— 所以这是一个潜伏的洞,不是现存的红。补上词表大概率仍然是绿的,应该顺手做掉。
建议
把
getServiceAsync(以及hasService之类真正读注册表的入口,如果确认存在)加进该脚本的lookup 词表,并补一条 self-test:
init()里未声明的getServiceAsync('X')必须判红。需要顺带核对
--list的边名输出(现在硬编码写作getService('X'))。为什么不在 #4777 里一并做
#4777 建立的是另一条规则(「读注册表可以,记账不行」),两条门禁互补:
#4471 说「你得声明」,#4777 说「你没声明就不许记账」。 扩 #4471 的词表是它自己的
scope,而且改动会波及一条与本次派发不同的判定语义,单独一 PR 更干净。
发现于:PR #4833(#4777)。