fix(plugin-dev): 请求组织墙而企业包不可用时拒绝 init (ADR-0093 D5) (#5301) - #6053
Draft
qq9340100 wants to merge 1 commit into
Draft
fix(plugin-dev): 请求组织墙而企业包不可用时拒绝 init (ADR-0093 D5) (#5301)#6053qq9340100 wants to merge 1 commit into
qq9340100 wants to merge 1 commit into
Conversation
DevPlugin 请求了有墙 posture 却加载不到企业 @objectstack/organizations 时, 只打一条 logger.warn 就继续 boot——同一台机器上,objectstack serve 对同一个 事实是拒绝启动。ADR-0093 D5 是部署的性质而非某个入口的性质,dev 装配路径欠 同一个答案。 改为 throw(不是 process.exit):DevPlugin 是库形态装配插件,对宿主进程没有 处置权;boot 链不吞异常(kernel.use 只登记、initPluginWithTimeout 不 catch、 bootstrap rethrow),与同文件 assertNotProduction() 的既有依据一致。 照 #4818 分两阶段:import 失败(缺包)受 OS_ALLOW_DEGRADED_TENANCY 管辖, 用的是 serve.ts 同一个 resolveAllowDegradedTenancy();construct/init 失败 (包在、插件自己拒绝)一律中止,hatch 不覆盖。阶段 2 在 DevPlugin 里多一处 落点——它自己 init 子插件的 best-effort 循环会吞掉 init 拒绝——故对这一个 子插件单独例外,其余子插件容错不变。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wbxm29qPKnLf44AbSxizqW
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
This was referenced Aug 6, 2026
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 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.
Fixes #5301
缺陷
DevPlugin请求了有墙 tenancy posture(isolated/group)却加载不到企业@objectstack/organizations时,只打一条logger.warn就继续 boot。于是同一台机器上,同一个事实有两个相反的答案:isolated、企业包缺失objectstack serveOS_ALLOW_DEGRADED_TENANCY=1)DevPlugin(改前)ADR-0093 D5「请求了隔离就不得在没有隔离的情况下服务流量」是部署的性质,不是某一个入口的性质,所以 dev 装配路径欠同一个答案。#5262 让这条更容易被触发而不是更难:在它之前,只设
OS_TENANCY_POSTURE的 dev 栈根本不进这个分支(那正是 #5262 本身的缺陷),修好读数之后它会进分支、会加载失败,然后正好走这条 fail-open 的路。前提已按最新
origin/main(739f496)复核:dev-plugin.ts的组织墙分支仍是单个try+ 只 warn 的catch,无任何 hatch 闸。改法
throw,不是process.exit(1)serve.ts必须process.exit,因为它那道闸嵌在会吞异常的 AuthPlugintry里;DevPlugin是库形态的装配插件,对宿主进程没有处置权,嵌入方(测试、脚本、父应用)有权 catch 它。而且它的 boot 链不吞异常——本 PR 已在当前 main 上复核该链仍成立:kernel.use()只登记(kernel.ts:180),initPluginWithTimeout只有try/finally没有catch(kernel.ts:565),bootstrap()的 catch 是this.state = 'stopped'; throw error;(kernel.ts:405)。所以throw能真的中止 boot,与同文件assertNotProduction()的既有依据一致。照 #4818 分两阶段,两种失败两种诊断
OS_ALLOW_DEGRADED_TENANCY生效。未设则拒绝 init,报文点名被请求的 posture 与全部出路;设了则照旧 warn 后降级继续,且该 warn 仍如实说明墙是 INACTIVE。判定用resolveAllowDegradedTenancy()——和serve.ts同一个 resolver,两个入口对「显式同意」的定义因此不可能漂移(手写=== '1'会让true/on/yes对 serve 有效、对 dev 无效,同一台机器同一份 .env)。serve.ts的理由相同。阶段 2 在 DevPlugin 里比 serve.ts 多一处落点
serve把插件交给kernel.use(),其 Phase-1 循环会 rethrow init 失败,所以 serve 不需要为此写任何东西。而DevPlugin自己 init 子插件,那个循环刻意是 best-effort(记一条 error 继续,dev 栈才能在缺包时照常起)。对这一个子插件,best-effort 默认就是同一个 fail-open——墙没起来,进程照样服务流量。因此只让它单独例外,其余子插件的容错完全不变(有专门的回归用例钉住这条边界)。若只镜像 construct 阶段而不管这处,本 PR 就会留下一个自己刚关掉的洞:包在、插件在
init()里拒绝,依旧无墙继续跑。测试
新增两个 suite,按「能不能诚实观察」切分:
dev-plugin-tenancy-failfast.test.ts—— 阶段 1。@objectstack/organizations是云私有包、在本 workspace 里真实缺席,所以 import 真的失败、真实的 catch 分支真的跑,不 stub 任何被测对象。含:拒绝 init、报文点名 posture 与出路、hatch 放行后降级 warn 仍诚实、hatch 真值词表与 serve 一致、未调用process.exit(这条断言能跑起来本身就是证明——process.exit(1)会把 test runner 一起带走)、以及无墙 posture 完全不受影响。dev-plugin-tenancy-mount-refusal.test.ts—— 阶段 2。「包在且拒绝」按定义无法在没有包的情况下观察,故 mock 仅提供 open-source workspace 不可能有的那一件东西(一个可解析的@objectstack/organizations),被测的拒绝语义全部留在dev-plugin.ts里。含 construct 拒绝、init 拒绝、两者都不被 hatch 放行,外加一个正向对照(包在且健康则正常挂载)——没有它,整个文件可能只是靠「有墙 posture 一律抛」而通过,那就什么也没钉住。已有的 #5262 suite 观察的是分支进入,它从 warn 那一行读这个信号;该路径现在 fail-fast,故其
beforeEach显式设上 hatch 并写明理由——降级路径仍在同一行点名被请求的 posture,#5262 钉的信号一字未失。反向验证(方向为事前预测,非事后解释):预测「把 warn-only 块放回去,新增的拒绝类断言应转红」——即常规的红向,因为新用例断言的是旧代码从不产生的拒绝。实测:仅还原
dev-plugin.ts、保留全部新测试,Tests 11 failed | 34 passed,红的恰好是 11 条拒绝类断言;正向对照、best-effort 边界回归、无墙用例与整个 #5262 suite 全部保持绿。方向与预测一致。消费半径已清扫:
new DevPlugin(全仓仅出现在本包内;examples/app-todo、scripts/analytics-reconcile等均显式OS_MULTI_ORG_ENABLED='false'(single posture,不进分支),packages/qa/dogfood为单组织bootStack,packages/cli的两个 organizations e2e 走的是serve.ts。本地另跑通 CI ESLint job 内的家族闸:
durability-log-level、startup-registry-verdict、error-code-casing、wildcard-fallthrough、init-service-contract、route-envelope、engine-double-contract、service-providers、published-files、role-word、doc-authoring全绿,check:nul-bytes与逐文件控制字符自扫描均干净,eslint packages/plugins/plugin-dev --no-inline-config退出 0。范围
⛔ 未改
packages/cli/src/commands/serve.ts(只读参照面)。已附@objectstack/plugin-devchangeset,内含迁移说明:依赖静默降级的 dev 栈需显式设OS_ALLOW_DEGRADED_TENANCY=1。Generated by Claude Code