fix(cli): os doctor 说出配置载入失败的原因,不再只说一句「载入不了」(#5403) - #5410
Conversation
The config-analysis `catch` took no binding — `catch {` — so the error
object was discarded at the point it was caught. A genuinely broken
config produced `Could not load config for analysis (config checks
skipped)` and nothing else, under any flag: the sentence came from a
bare `printWarning`, not from a `HealthCheckResult`, so `--verbose` had
no `fix` to expand. `os serve`, in the same directory, prints the error
in full — the diagnostic command returned strictly less than the command
it exists to diagnose.
#5382 / #5387 / #5397 fixed this sentence's ATTRIBUTION. This fixes what
it SAYS now that it is finally saying it about the right thing.
- `configLoadFailureCheck(err)` builds an ordinary `HealthCheckResult`,
quoting the thrower verbatim (#5390's `cause:` posture) rather than
paraphrasing: the failure can come from user code, esbuild, Node's
resolver, or `loadConfig()` itself.
- `renderHealthCheckResult()` extracts the environment block's rendering
so the finding travels the same path and the same `--verbose` rule as
`Environment files` / `Tenancy posture`, deleting the bare-printWarning
bypass that had no `fix` channel at all.
- The row carries a whitespace-folded, bounded quote (esbuild's first
line is its least informative one); `--verbose` carries the untruncated
original.
- Gauge unchanged: warning, rest of the report runs, exit 0. The
recognizable sentence survives verbatim as the head of the row —
sibling tests assert its absence to mean "the config loaded".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 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:
|
验证(正文「命令与结果见下方」指向此处)会话: 全包测试 typecheck doctor 四个文件合并跑(含三份兄弟测试,确认未回归) 其中 仓库门禁 / lint 反向验证 的事前预测与逐条实测已写在 PR 正文;要点是 2 条否定式 e2e 在回退下仍绿,这是断言「不出现」的结构性上限,不是覆盖漏洞 —— 正向用例即为此存在。 Generated by Claude Code |
Fixes #5403
前提核验(先于实现)
issue 引用的行号
98369a86b:1212已因同日 churn 漂移,但事实成立。origin/main(4b61cf3)上该 catch 仍为:packages/cli/src/commands/doctor.ts:1320。不带绑定,error 当场丢弃;这句话是裸printWarning,不是HealthCheckResult,所以--verbose根本没有fix可展开 —— issue 正文「没有任何旗标能让操作者看到更多」的判断经核实为真。采用的方案:PM 指定的方案二(未退回最小改法)
裸
printWarning改为一条常规HealthCheckResult,与Environment files/Tenancy posture走同一个渲染器、同一条--verbose展开规则。方案二在本文件里有一处需要处理的时序事实,但不构成语义冲突:环境检查那个
results.forEach在报告较早处就跑完了,而 config 载入发生在它之后 —— 把行 push 进results让老循环去打是打不出来的。解法不是重排报告(那会把结论挪离产生它的那一步,是超出判定面的输出契约变动),而是把渲染规则从循环体里提成具名函数renderHealthCheckResult(),两处共用。这样「统一渲染 + 统一 verbose 展开 + 消灭裸 printWarning 旁路」三条都成立,报告顺序一字未动。行同时仍 push 进results,让该轮的记录保持完整(今日惰性:末尾 fix 汇总按error过滤)。效果
(以上为真机 in-process 运行捕获的输出,非手写示意。)
四条刻意的取舍
os doctor指名道姓报告非法OS_TENANCY_POSTURE并非零退出 (#5382) #5390 姿态)。配置载入的失败来自四个不同权威:用户自己的throw、esbuild 的打包诊断、Node 的模块解析、loadConfig()自己的 "no default export"。doctor 没有立场把它们总结得比它们自己更好。message,而不只进fix。Environment files把 cause 只放fix是对的 —— 那一行本身已把结论说完整,cause 是脚注。这里 cause 就是结论:没有它,这一行只说了「出了点没被指名的问题」,默认运行仍然严格少于os serve。所以平铺一行放收敛后的引文,--verbose给未截断的原文。Build failed with 1 error:,文件与原因在下一行)。空白折叠 + 超长截断,词序全是上游的,只有换行和过长的尾巴是我们的。反向验证(方向:红,事前预测)
预测:仅把调用点回退为裸
printWarning(builder 保留导出),则 8 条 builder 单测保持绿(被测对象未动),3 条正向 e2e 转红,2 条否定式 e2e 仍绿(它们断言「不出现」,结构上不可能察觉该回退 —— 这正是正向用例存在的理由)。实测逐条命中:承重件:#5397 的 async overlay 未受影响
loadConfig()仍在withDotenvOverlayAsync内,一字未动 —— 同步 overlay 包不住bundleRequire的动态import()。新增用例正面钉住:只因缺.env值才抛错的配置不得走到这条路径(否则该行会出现),且 overlay 事后不留残留。测试
packages/cli/src/commands/doctor-config-load-cause.test.ts(新增 13 例,全部按车道纪律显式60_000超时):name列;指向os serve且声明被跳过的检查「SKIPPED, not passed」;多行 cause 折叠后不丢信息行;超长 cause 行内截断而fix完整;new TypeError()无 message 时不以裸破折号收尾;throw 'boom'/throw 42等非 Error 也被报出。--verbose展开且仅在 verbose 展开;语法错误报出文件名;os doctor载入objectstack.config.ts时不带.env*overlay —— 配置文件自己读process.env时,doctor 报「Could not load config」而os serve同目录正常启动 #5397 未回归;配置正常时该行完全不出现。命令与逐条结果见本 PR 的「验证」评论(全包 728 例绿、typecheck 绿、六项仓库门禁与 eslint 绿)。
越界情况
改动仅落在
packages/cli/src/commands/doctor.ts+ 同目录测试 + 一份 changeset,与派发口径的文件面一致。已按消费半径搜过Could not load config/config checks skipped/Loading configuration for analysis全仓引用:除本文件与测试外只剩两份历史 changeset(#5382 / #5397 的),它们记述当时事实,不应改写。顺带核验发现、未在本 PR 修的一条,已另行开单:#5412 —— 同文件
readInstalledPackageEntries()的 catch 把「可选包没装」和「ledger 里的 manifest 损坏」当成同一件事,导致 ADR-0120 D5e 的 unique-scope 建议静默少报并打出✓ ... No unconfirmed installation-wide uniques(false PASS)。同族、低一层,但属于另一处 catch、另一条检查的判定面,且「读不到 ledger 时还能否声称 clean」是需要判定的决策点,不宜夹带。