发现于 #5262 的开发(会话 session_015W6nhsDrz6zWQc8je12a1t),不在该 PR 范围内:#5262 只订正各站点读哪个 knob,不改任何站点的失败语义。按 Prime Directive #10 单独归档,不指派。
缺陷
packages/plugins/plugin-dev/src/dev-plugin.ts 在请求了有墙 posture 时会尝试加载企业 @objectstack/organizations;加载失败只打一条 logger.warn 就继续 boot:
if (multiTenant) {
try {
const mod: any = await import(organizationsPkg);
this.childPlugins.push(new mod.OrganizationsPlugin());
} catch {
ctx.logger.warn(` ✘ tenancy posture '...' requested but @objectstack/organizations (enterprise) not installed — running single-org, organization wall INACTIVE (ADR-0093 D5)`);
}
}
packages/cli/src/commands/serve.ts 在同一个事实上的处理是 ADR-0093 D5 的 fail-fast:分两阶段(import 失败 = 包缺失,construct/mount 失败 = 插件自己拒绝),缺包时除非 OS_ALLOW_DEGRADED_TENANCY=1 否则 process.exit(1),且该 hatch 明确不覆盖 mount 阶段的拒绝(#4818)。
于是同一台机器上:
| 入口 |
请求 isolated、企业包缺失 |
结果 |
objectstack serve |
拒绝启动(除非显式 OS_ALLOW_DEGRADED_TENANCY=1) |
安全 |
DevPlugin |
warn 后继续 |
无墙服务流量,且没人显式同意过 |
即 ADR-0093 D5「请求了隔离就不得在没有隔离的情况下服务流量」在 dev 装配路径上没有被强制。#5262 修好读数之后这条反而更容易被触发:在此之前,只设 OS_TENANCY_POSTURE 的 dev 栈根本不进这个分支(那是 #5262 本身的缺陷);现在它会进分支、会尝试加载、会失败,然后走这条只 warn 的路。
为什么单独归档而不是顺手补
把 process.exit(1) 加进 plugin-dev 是行为变更,不是 knob 订正:
DevPlugin 是库形态的装配插件,不是 CLI 进程的所有者,process.exit 在这里的正当性和在 serve.ts 里不同(serve 的注释明确说明它必须 process.exit 而非 throw,因为它嵌在会吞异常的 AuthPlugin try 里;plugin-dev 的调用环境不同,throw 可能才是对的——assertNotProduction() 就是 throw)。
- 语义要跟
OS_ALLOW_DEGRADED_TENANCY 对齐还是另立一套(dev 场景下要不要更宽松),是维护者的判断。
建议
对齐 serve.ts 的 D5 语义:请求了有墙 posture 而企业包不可用时,除非 OS_ALLOW_DEGRADED_TENANCY 为真否则拒绝 init(用 throw,与同文件 assertNotProduction() 一致——kernel.use() 只登记、initPluginWithTimeout 不 catch、bootstrap() 会 rethrow,所以 throw 能真的中止 boot)。是否也照 #4818 分 import / mount 两阶段,一并请维护者定。
出处:#5262 的 PR(分支 claude/issue-5262-posture-misreads)。
发现于 #5262 的开发(会话
session_015W6nhsDrz6zWQc8je12a1t),不在该 PR 范围内:#5262 只订正各站点读哪个 knob,不改任何站点的失败语义。按 Prime Directive #10 单独归档,不指派。缺陷
packages/plugins/plugin-dev/src/dev-plugin.ts在请求了有墙 posture 时会尝试加载企业@objectstack/organizations;加载失败只打一条logger.warn就继续 boot:packages/cli/src/commands/serve.ts在同一个事实上的处理是 ADR-0093 D5 的 fail-fast:分两阶段(import 失败 = 包缺失,construct/mount 失败 = 插件自己拒绝),缺包时除非OS_ALLOW_DEGRADED_TENANCY=1否则process.exit(1),且该 hatch 明确不覆盖 mount 阶段的拒绝(#4818)。于是同一台机器上:
isolated、企业包缺失objectstack serveOS_ALLOW_DEGRADED_TENANCY=1)DevPlugin即 ADR-0093 D5「请求了隔离就不得在没有隔离的情况下服务流量」在 dev 装配路径上没有被强制。#5262 修好读数之后这条反而更容易被触发:在此之前,只设
OS_TENANCY_POSTURE的 dev 栈根本不进这个分支(那是 #5262 本身的缺陷);现在它会进分支、会尝试加载、会失败,然后走这条只 warn 的路。为什么单独归档而不是顺手补
把
process.exit(1)加进plugin-dev是行为变更,不是 knob 订正:DevPlugin是库形态的装配插件,不是 CLI 进程的所有者,process.exit在这里的正当性和在serve.ts里不同(serve 的注释明确说明它必须process.exit而非throw,因为它嵌在会吞异常的 AuthPlugintry里;plugin-dev 的调用环境不同,throw可能才是对的——assertNotProduction()就是throw)。OS_ALLOW_DEGRADED_TENANCY对齐还是另立一套(dev 场景下要不要更宽松),是维护者的判断。建议
对齐
serve.ts的 D5 语义:请求了有墙 posture 而企业包不可用时,除非OS_ALLOW_DEGRADED_TENANCY为真否则拒绝 init(用throw,与同文件assertNotProduction()一致——kernel.use()只登记、initPluginWithTimeout不 catch、bootstrap()会 rethrow,所以 throw 能真的中止 boot)。是否也照 #4818 分 import / mount 两阶段,一并请维护者定。出处:#5262 的 PR(分支
claude/issue-5262-posture-misreads)。