Uh oh!
There was an error while loading. Please reload this page.
fix(cli): ledger 可读性提为 posture 无关的独立健康检查,D5e 只留 unique-scope 判断 (#5429) - #5988
Conversation
…ancy posture (#5429) The three rows that say `os doctor` could not read `.objectstack/installed-packages/` — the directory could not be enumerated (#5412), a file inside it would not parse (#5413), the ledger reader would not load (#5644) — were all built inside the ADR-0120 D5e unique-scope advisory, whose entry condition is `postureGatesGlobalUniques(posture)`. That is true only for `isolated`, so under `single` and `group` `readInstalledPackageEntries()` was never called and doctor said nothing at all. `OS_TENANCY_POSTURE` unset resolves to `single`, so the blind posture was the default one. Per the maintainer's 2026-08-06 ruling (option A), ledger readability is now its own posture-independent check under the `Installed packages` name, read once per run, outside the posture gate and outside the config-analysis block. The D5e block keeps the unique-scope judgment alone and consumes the same reading, so one bad ledger produces one row under `isolated` too; an incomplete reading still withholds `✓ Unique scope` there. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DWUR56YsttL5sTF72Q75TQ
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:
|
baozhoutao
commented
Aug 6, 2026
越界发现,已另开、未修:#5996(观察类, Generated by Claude Code Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#5429
按维护者 2026-08-06 裁定的 方向 A 实施:把「installed-package ledger 可读性」提成一条 posture 无关的独立健康检查,ADR-0120 D5e 块只保留 unique-scope 判断本身。
前提复核(以 origin/main
5582e1821为准)前提成立,且比 issue 描述的更宽:
os doctor的 installed-package ledger 读取 catch 把「损坏」和「没装」当成同一件事 —— D5e 建议因此静默少报,并打出「clean」 #5412 目录级、LocalManifestSource.list()静默丢弃损坏的 ledger 条目 —— 已装应用在 boot 时消失、在控制台列表里缺席,且没有任何一条日志 #5413 条目级)之外,os doctor把「cloud-connection 没装」和「装了但加载不了」当成同一件事 —— ledger 目录在场也照打 clean bill(#5412 假 PASS 的上一层) #5644 之后又多了第三条(reader 级Could not load the installed-package ledger reader,2026-08-05 22:45 UTC 合并,早于裁决评论)。三条同属「ledger 读不动」这一族,同样锁在 D5e 块里,同样只在isolated下存在 —— 裁决口径「无条件执行readInstalledPackageEntries()可读性判定」对三条一体适用,只留一条在门内会把同一族切成两半。resolveTenancyPosture()在OS_TENANCY_POSTURE未设、多租户未开时返回single(packages/types/src/env.ts:161)。也就是说开箱默认的 posture 恰好就是失明的那个 —— 不是「换个 posture 才踩到」,是「不设变量就踩到」。改了什么
os doctor只读一次,读在run()里、posture 门之外、configExists()块之外。installedPackageLedgerChecks(reading)把这一次读的结果翻成 0~2 行(reader 级与另外两级互斥),推进既有results表,由同一个renderHealthCheckResult渲染。configExists():ledger 可读性读的是一个目录,不依赖 config。留在 config 块里等于把 posture 门换成 config 门 —— 同一种沉默换个条件,os doctor对非法OS_TENANCY_POSTURE退出码 0 并报告「环境功能正常」—— 抛错被 config 分析的宽 catch 吞成一句「Could not load config」 #5382 当初给 posture reader 做的加宽正是同一理由。findUnscopedGlobalUniques()不再自己读 ledger、也不再回传三个失败事实,改为接收已读好的entries。没有第二次读、没有第二个报告者,isolated下同一个坏 ledger 只可能出现一次。✓ Unique scope。 那行成功语是对 advisory 两个半边的断言,ledger 半边只要没读全(目录读不动 / 条目读不动 / reader 没加载),它就不能印 ——os doctor的 installed-package ledger 读取 catch 把「损坏」和「没装」当成同一件事 —— D5e 建议因此静默少报,并打出「clean」 #5412/LocalManifestSource.list()静默丢弃损坏的 ledger 条目 —— 已装应用在 boot 时消失、在控制台列表里缺席,且没有任何一条日志 #5413/os doctor把「cloud-connection 没装」和「装了但加载不了」当成同一件事 —— ledger 目录在场也照打 clean bill(#5412 假 PASS 的上一层) #5644 在这里活下来的部分只剩这一条。Unique scope→Installed packages。 原名在「只可能出现在 D5e 块内」时是对的(让操作者扫的那一行在场而不是缺席);检查一旦 posture 无关,single/group下压根没有 unique-scope 检查,用它命名就是在报一个当下不存在的检查。message 的括号同步去掉for installation-wide uniques四个词,其余原文一字未动(installed packages NOT checked保留,操作者 grep 的就是它)。Unique scope这个名字仍在,仍归 D5e 的 unique-scope 判定独有。readInstalledPackageEntries()里path.join(cwd, mod.DEFAULT_INSTALLED_PACKAGES_DIR ?? …)挪进try。它不再跑在别人的try里了,一个非字符串导出以前会被 config 的catch吞成「Could not load config for analysis」的误报,现在只能是它自己那一行。与 boot 侧
rehydrate()warn 的分工(裁决要求写明)两路各自成立,互不替代,本 PR 未动 runtime/metadata-protocol 一行:
rehydrate()每条损坏条目warnos doctor的Installed packages行isolated下 D5e 少看了一半boot 侧本来就与 posture 无关,所以操作者不是全无信号 —— 缺的是诊断命令这一路。两面口径不一致正是 #4801 / cloud#1020 那一族;#5429 前它们确实不一致。
验证 / 反向验证
方向事先预测,两个扰动分别打在两条验收线上,结果与预测一致:
single/group各 3 条 + 未设 posture + 无 config),失败输出显示整张报告里没有任何 ledger 行 —— 不是文案不符,是这条检查根本没发生。改完后同样 8 条转绿。isolated去重钉子红。实测reports an unreadable DIRECTORY exactly once/reports a corrupt ENTRY exactly once两条转红(出现次数 1 变 2)。这一条是特意做的:去重钉子在 main 上本来就是绿的(今天只有一个报告者),不证伪一次就分不清「钉住了」和「恰好为空所以过」—— PR fix(lint): 收敛 validate-expressions / validate-security-posture 的 spec 不声明键??别名读法 (#5017) #5046 记过这个坑。验收对照
single/group(以及未设 posture、无 config)下,目录级与条目级各有其行 ——describe.each(BLIND_POSTURES)六条 + 两条单独用例;isolated下同一个坏 ledger 只报一次 —— 出现次数计数钉住,且✓ Unique scope仍被扣住;--verbose);@objectstack/clipatch;doctor-ledger-read-failure.test.ts(#5412/#5413/#5644 的既有钉子)全部保留、逐条复核:除 name 列 5 处随改名更新外,isolated下的报告面一字未变 —— 这一点是刻意的,新检查可达不等于旧报告可以漂。一处需要下游知道的事
已合并待发布的 changeset
quiet-ledgers-speak-up.md里写着「os doctorreports unparseable entries as aUnique scopewarning row」。发布时该句已被本 PR 取代,我没有去改别人的 changeset,而是在本 PR 的 changeset 里显式写明「supersedes」,由发布流程合并两条时择取。🤖 Generated with Claude Code
https://claude.ai/code/session_01DWUR56YsttL5sTF72Q75TQ
Generated by Claude Code