实施 #5403(给 config 分析的 catch 加上 error 绑定)时顺带核验发现;未在该 PR 里改 —— #5403 的判定面被限定为 config 分析那一个 catch 的输出,本条是另一处 catch、另一条检查的判定面。
事实
packages/cli/src/commands/doctor.ts:771-784(origin/main 4b61cf3):
/** Read the installed-package ledger without going through HTTP. Best-effort:
* a runtime that never installed anything simply has no directory. */
async function readInstalledPackageEntries(cwd: string): Promise<any[]> {
try {
const mod: any = await import('@objectstack/cloud-connection');
const dir = path.join(cwd, mod.DEFAULT_INSTALLED_PACKAGES_DIR ?? '.objectstack/installed-packages');
if (!fs.existsSync(dir)) return [];
return new mod.LocalManifestSource(dir).list();
} catch {
return [];
}
}
这个 catch 不带绑定,且覆盖了两件性质完全不同的事:
import('@objectstack/cloud-connection') 解析不到 —— 可选包没装。注释写明了这一条,而且是对的:doctor 必须能在没有该包的 checkout 里跑完。
new mod.LocalManifestSource(dir).list() 抛错 —— 目录存在(fs.existsSync(dir) 已经通过),但里面某个 manifest 损坏 / 不可读 / JSON 解析失败。
第 2 种被当成第 1 种处理,一律 return []。
后果
唯一的消费者是 ADR-0120 D5e 的 unique-scope 建议(findUnscopedGlobalUniques,同文件 792-815):它把「本项目 metadata 的 findings」和「ledger 里已装包的 findings」拼在一起。ledger 那一半返回空数组时,doctor 走的是 else 分支:
✓ Unique scope No unconfirmed installation-wide uniques for this 'isolated' environment
也就是说,一个装了包、但 ledger 损坏的 isolated 环境,拿到的是一张干净的体检单,而不是「有一部分我没能读到」。这比报一条 warning 更糟:false PASS 会让操作者停止查看。
与 #5403 是同一族(诊断命令自己吞掉了唯一能解释状况的那个对象),但低一层:#5403 里被吞的是「检查跑不了」的原因,这里被吞的是「检查跑了一半」这个事实本身 —— 连「有东西没读到」都没说。也属于 #4801 / cloud#1020 的「诊断面与运行时不一致」家族。
复现路径(未在真机执行,静态可判)
前提:OS_TENANCY_POSTURE=isolated,.objectstack/installed-packages/ 存在且至少一个条目损坏(截断的 JSON、权限不可读)。预期得到上面那行 ✓ Unique scope,而不是任何提示。
可能的方向(供分诊,不预设)
备注
实施 #5403(给 config 分析的 catch 加上 error 绑定)时顺带核验发现;未在该 PR 里改 —— #5403 的判定面被限定为 config 分析那一个 catch 的输出,本条是另一处 catch、另一条检查的判定面。
事实
packages/cli/src/commands/doctor.ts:771-784(origin/main4b61cf3):这个
catch不带绑定,且覆盖了两件性质完全不同的事:import('@objectstack/cloud-connection')解析不到 —— 可选包没装。注释写明了这一条,而且是对的:doctor 必须能在没有该包的 checkout 里跑完。new mod.LocalManifestSource(dir).list()抛错 —— 目录存在(fs.existsSync(dir)已经通过),但里面某个 manifest 损坏 / 不可读 / JSON 解析失败。第 2 种被当成第 1 种处理,一律
return []。后果
唯一的消费者是 ADR-0120 D5e 的 unique-scope 建议(
findUnscopedGlobalUniques,同文件792-815):它把「本项目 metadata 的 findings」和「ledger 里已装包的 findings」拼在一起。ledger 那一半返回空数组时,doctor 走的是else分支:也就是说,一个装了包、但 ledger 损坏的 isolated 环境,拿到的是一张干净的体检单,而不是「有一部分我没能读到」。这比报一条 warning 更糟:false PASS 会让操作者停止查看。
与 #5403 是同一族(诊断命令自己吞掉了唯一能解释状况的那个对象),但低一层:#5403 里被吞的是「检查跑不了」的原因,这里被吞的是「检查跑了一半」这个事实本身 —— 连「有东西没读到」都没说。也属于 #4801 / cloud#1020 的「诊断面与运行时不一致」家族。
复现路径(未在真机执行,静态可判)
前提:
OS_TENANCY_POSTURE=isolated,.objectstack/installed-packages/存在且至少一个条目损坏(截断的 JSON、权限不可读)。预期得到上面那行✓ Unique scope,而不是任何提示。可能的方向(供分诊,不预设)
import()单独 try(可选包缺失 = 静默,现状正确),list()的抛错另行处理;list()失败时产出一条常规HealthCheckResult(os doctor的 config 分析 catch 丢弃了 error 本身 —— 配置真坏掉时只说「载入不了」,不说为什么 #5403 刚把renderHealthCheckResult()提成具名函数,这条路径可以直接复用),措辞按 fix(cli):os doctor指名道姓报告非法OS_TENANCY_POSTURE并非零退出 (#5382) #5390 体例引上游原话;备注
doctor/installed-packages/ledger),未见重复;唯一命中是os doctor的 config 分析 catch 丢弃了 error 本身 —— 配置真坏掉时只说「载入不了」,不说为什么 #5403 自身。os doctor的 config 分析 catch 丢弃了 error 本身 —— 配置真坏掉时只说「载入不了」,不说为什么 #5403 无依赖关系,独立成单(os doctor的 config 分析 catch 丢弃了 error 本身 —— 配置真坏掉时只说「载入不了」,不说为什么 #5403 的 PR 只动 config 分析那个 catch,不触及本函数)。