fix(plugin-auth,plugin-webhooks): retire a dead degrade branch and an implicit transitive dependency (#4187) - #4211
Merged
Conversation
… implicit transitive dependency (#4187) Two concrete findings from the ADR-0116 consumer-side audit, plus the authoring rule that would have prevented both. plugin-auth claimed a fallback it did not have: init() ran `const dataEngine = ctx.getService('data'); if (!dataEngine) { warn(... "auth will use in-memory storage") }`. That branch could never execute — getService THROWS for an unregistered service rather than returning undefined, and this plugin declares a hard dependency on ObjectQL (which registers `data` unconditionally), so a kernel without the engine fails earlier still with "Dependency ... not found". The branch is removed and the real contract declared as requiresServices: ['data', 'manifest'], which also replaces a trailing `// manifest service required` comment with the machine-checked form of the same claim. AuthManager keeps its own optional dataEngine guards — it is usable outside the plugin. plugin-webhook-outbox was protected only transitively: it resolves `manifest` in init() with no fallback while depending on messaging, which in turn depends on ObjectQL, the actual provider. That would have broken silently the day messaging stopped depending on the engine, and surfaced as a crash inside an unrelated plugin's init. It now declares requiresServices: ['manifest'] directly. Neither change alters ordering or boot outcomes on any current composition — both plugins were already ordered correctly. What changes is what a broken composition says, and that the guarantees are checked rather than inherited. Docs: anatomy.mdx gains the three ADR-0116 fields and the decision rule for resolving a service inside init(), including the two traps behind these fixes. The api-registry example declares the contract on all seven of its plugins instead of relying on kernel.use() order. Refs #4187 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014DQuJBNpwStpJvo3owBw2B
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 27 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
收尾 #4187 的第 1–3 项(第 4 项见文末)。两处具体缺陷 + 一条本可以预防它们的编写规则。
1.
plugin-auth宣称了一个它并不具备的降级模式init()里原本是:这条分支永远不会执行,两重原因叠加:
getService在服务未注册时是抛错,不会返回undefined;com.objectstack.engine.objectql,而后者无条件注册data。没有引擎的内核会更早死在Dependency 'com.objectstack.engine.objectql' not found。也就是说它宣传的 "in-memory storage" 是一个组装方式本身就禁止的模式。删掉分支,并把真实契约声明出来:
requiresServices: ['data', 'manifest']——顺带把原来那句行尾注释// manifest service required换成了机器可校验的同一主张。AuthManager内部的dataEngine?判空保留不动:它可以脱离本插件独立使用,那些判空在别的调用场景下是有意义的。2.
plugin-webhook-outbox只被传递依赖保护着它在
init()里无兜底地取manifest,却只声明dependencies: ['com.objectstack.service.messaging']——靠 messaging 恰好依赖 ObjectQL 才成立。这条链哪天断了(messaging 不再依赖引擎),故障会以"另一个插件 init 崩溃"的形式出现,排查方向完全错位。改为直接声明requiresServices: ['manifest']。两处改动都不改变任何现有组装的排序或启动结果——它们本来就排对了。改变的是组装出错时的报错内容,以及这份保证从"继承来的"变成"被校验的"。
3. 把规则写进文档
content/docs/plugins/anatomy.mdx:补上 ADR-0116 的三个字段,以及"在init()里同步取服务该怎么声明"的二选一表格(硬dependenciesvsoptionalDependencies+requiresServices),并明确写进促成本 PR 两个修复的两个坑:getService后面写if (!svc) { 降级 }——那是死代码,宣传了一个不存在的模式。顺手把
api-registry-example.ts里 7 个插件全部补上声明。原先它们全靠kernel.use()顺序工作,而示例正是模式被复制的源头;只改其中 2 个会让示例自相矛盾,所以要么都改要么都不改。4. D4(服务声明自动推导排序)本次仍不做
证据继续支持"不做":provider 侧刚补齐(#4185),消费方侧 12 个一致地选择了硬依赖,说明"硬依赖排序 + 服务声明校验/诊断"这套两级机制已经覆盖了真实用法。等出现第二、第三个像
AppPlugin那样的软依赖消费方再回头看。#4187 保持 open 记录这一项。验证
pnpm build71/71 通过。pnpm test运行中(退出码写入独立文件,不走管道——本次会话早先在这上面误报过一次)。🤖 Generated with Claude Code
https://claude.ai/code/session_014DQuJBNpwStpJvo3owBw2B
Generated by Claude Code