fix(cli): os doctor 指名道姓报告非法 OS_TENANCY_POSTURE 并非零退出 (#5382) - #5390
Merged
Conversation
doctor 的两处 posture 读取都在 config 分析那个很宽的 try 里,抛错被它的 catch 转述成「Could not load config for analysis」并只记 warning —— 一个 os serve 会拒绝启动的环境,os doctor 报「Environment is functional」+ exit 0, 全程不出现 OS_TENANCY_POSTURE 这个词。归因错了,严重级也错了。 现在在 run() 顶部、任何 try 之外解析一次,非法值产出一条普通的 error 体检项 (修法清单由 TENANCY_POSTURES 生成,cause 直接引用解析器原话),由 doctor 自己的错误汇总给出非零退出码 —— 不 process.exit,doctor 的语义是「报告」。 两处读取复用同一个已解析值。 顺带:那两处此前都在 if (configExists()) 之内,没有配置文件的环境从来没读过 posture;现在与是否存在配置文件无关。 残留(文案里如实写明,另记为 #5387):doctor 不加载 .env*,写在 .env 里的 非法 posture 仍到不了这份报告。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VkPSGsX9o17MsGv3Lbxu2w
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 21 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
…tor-posture-report
Contributor
Author
|
合入 文件面无重叠(#5381 只动 Generated by Claude Code |
baozhoutao
marked this pull request as ready for review
August 5, 2026 04:30
baozhoutao
enabled auto-merge
August 5, 2026 04:30
This was referenced Aug 5, 2026
Closed
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 #5382
前提核验:成立,而且比 issue 描述的更糟
先在
origin/main(ada0b84a3,#5380/#5385 已合入)上把 issue 的复现跑了一遍 —— 真机运行doctor命令,临时 cwd 里放一个能正常载入的objectstack.config.ts,OS_TENANCY_POSTURE=bogus:注意
✓ Platform spec那一行:配置是载入成功了的,checkSpecVersionGap都已经跑完并通过,之后才轮到doctor.ts:688的 posture 抛错被同一个try的 catch 接住。所以「Could not load config」这句话不只是归因不准,它是字面上的假话 —— config 载进来了。issue 的判断完全成立。顺带发现 issue 没提到的一半:那两处 posture 读取都在
if (configExists())之内。所以在没有objectstack.config.ts的环境里,doctor 连那句归因错误的 warning 都不会有 —— posture 从头到尾没被读过,零信息、exit 0:改了什么
按 PM 裁定的方向 1:在
run()顶部、任何try之外解析一次 posture,非法值报 error 并计入hasErrors,不process.exit(1)—— doctor 的语义是「报告」,报告照常跑完,由它自己的错误汇总给出退出码。修完之后,同一个环境(真机运行
bin/run.js doctor):@objectstack/spec/security的TENANCY_POSTURES生成,不是第二份字面量 —— 新增一个 posture 不会让这段建议悄悄过期(有测试钉住)。cause直接引用@objectstack/types解析器自己那句话,doctor 不维护会跟它跑偏的第二份措辞。doctor.ts:688的 D5e 闸门、findUnscopedGlobalUniques())现在复用同一个已解析值;findUnscopedGlobalUniques改为接收 posture 参数,resolveTenancyPosture()在整个文件里只剩包装器内那一处调用。与 PR #5381(serve)的关系:同形,不同裁决,没有复用它的代码
范本是 #5381 的
resolveTenancyPostureOrRefusal,本单是resolveTenancyPostureOrFinding,刻意分开:serve(#5359 / PR #5381)doctor(本单)process.exit(1)error体检项,报告跑完后由汇总退出os serverefuses to boot this environment」——doctor 自己不启动任何东西.envdotenvFlow.config()之后,所以明说「检查了每个 .env」.env*,所以明说「没看 .env」没有从
serve.tsimport,理由有二:文案在三处都必须不同(照搬会让 doctor 谎称自己检查过.env、谎称拒绝启动);且serve.ts是 2800 行、拖着整条启动依赖图的模块,让doctor为一个纯函数把它整个拉进来不划算。两份加起来约 40 行、共享同一个TENANCY_POSTURES来源。去重机会属实存在(一个utils/tenancy-posture.ts放共同的 verdict 形状 + hints 表,两边各自拼文案),但那要动serve.ts—— 本单文件面被限定在doctor.ts,按派发口径不扩面,记在这里供后续裁定。测试
新增
packages/cli/src/commands/doctor-tenancy-posture-report.test.ts(11 例)。此前packages/cli对 doctor 的该行为零测试。TENANCY_POSTURES里每个值、legacymulti⇒isolated、未设置时走OS_MULTI_ORG_ENABLED派生、空白值等同未设置。status必须是'error'(这个字段才是驱动hasErrors→ 非零退出的那个,写成'warning'就复现了缺陷)、指名变量与用户实际敲的值、修法清单覆盖每个 posture、cause引用原话、以及不出现「Could not load config」/「config checks skipped」。doctor命令的差分对照 —— 同一个临时 cwd、同一套检查,只改OS_TENANCY_POSTURE一个变量。关于那个端到端用例的两点自我约束:
node_modules/。否则 doctor 的Dependencies检查自己就是error、自己就会 exit 1 —— 那样「exit 1」这条断言会因为与本改动无关的理由通过,是个假绿。反向验证(方向在跑之前就定了:标准的 before-red / after-green)。 把
doctor.tsstash 回origin/main状态、只留测试,端到端用例如预期变红,红的方式正是缺陷本身:输出里OS_TENANCY_POSTURE一次都没出现、process.exit从未被调用、结尾是「Environment is functional」。上面「前提核验」那两段输出就是这次反向跑的原始输出。改动前的整包基线同样是 660 通过(除了新测试文件本身的 11 红),所以没有既有用例被这条新增的 error 行影响。另跑:
check:nul-bytesOK、check:durability-log-levelOK、check:startup-registry-verdictOK、check:role-wordOK、check:error-code-casingOK、check:wildcard-fallthroughOK、eslint 干净;控制字符自查(grep -naP扫\x00-\x08\x0b\x0c\x0e-\x1f)三个文件均无裸控制字节。顺带发现(已另开 issue,未在本 PR 修)
os doctor不加载.env*,读到的环境与serve/dev/start实际运行的不是同一份 —— 写在.env里的配置错误 doctor 一律看不见 #5387 ——os doctor不加载.env*,而serve/dev/start都用 dotenv-flow 加载。于是写在提交进仓库的.env里的非法 posture,doctor 报绿、serve 拒绝启动。本单修好的「doctor 与 serve 不一致」,在.env这条来源上仍然成立,只是从「归因错误」缩小成「完全看不见」。文案里已如实写明不冒充检查过。没有顺手改的原因写在那单里:它会改变 doctor 每一项(现在的和将来的)env 派生检查的输入,还得选一个 doctor 并没有对应旗标的node_env,属于诊断输出的契约变化。另外两处看过、判断为不需要动:
packages/cli/src/commands/migrate/plan.ts:104/118的resolveTenancyPosture()也在一个宽try里,但它的 catch 是printError(error.message)+this.exit(1)—— 消息里带着变量名、退出码是 1。缺处方,但不是本单这个「exit 0 + 归因错误」的缺陷,不构成 finding。fix文本会被打印两次(结果行一次、结尾汇总再一次),这是它对所有 error 行的既有行为(Node.js、pnpm、Dependencies都如此),只是本单的 fix 较长所以显眼。改它会连带改掉其它行的汇总提示,属于 doctor 输出契约的另一个决定,没有搭车。🤖 Generated with Claude Code
https://claude.ai/code/session_01VkPSGsX9o17MsGv3Lbxu2w
Generated by Claude Code