Skip to content

fix(cloud-connection,cli): LocalManifestSource.list() 报告读不出来的 ledger 条目 (#5413) - #5424

Merged
baozhoutao merged 1 commit into
mainfrom
claude/issue-5413-manifest-source-skipped-entries
Aug 5, 2026
Merged

fix(cloud-connection,cli): LocalManifestSource.list() 报告读不出来的 ledger 条目 (#5413)#5424
baozhoutao merged 1 commit into
mainfrom
claude/issue-5413-manifest-source-skipped-entries

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Fixes #5413

缺陷

.objectstack/installed-packages/ 下一个截断 / 不可读 / 解析失败的文件,被 list()每文件不带绑定的 catch 就地丢掉,而 list() 返回一个裸数组 —— 短列表和完整列表在调用方看来完全一样:返回值上没有差别,没有日志,没有计数。抛出的对象在 catch 处就被丢弃了。三个消费者因此都给出了「静默的错答案」:

  • rehydrate():那个已装应用不被注册进 kernel —— 从这个 runtime 里消失(app switcher 里没有、对象不存在),日志里一个字都没有;
  • handleList():控制台「已安装应用」清单少一项,success: true
  • os doctor(ADR-0120 D5e):对一份自己从没解析过的 manifest 打出 ✓ Unique scope

跳过是对的(一个坏文件不该让整个 runtime 起不来),有意不说才是缺陷 —— issue 的定性照搬到这里仍然成立。

改法:分诊裁定的方案 A(契约优先)

list() 改为返回 { entries, skipped }skippedArray< { file: string; cause: unknown } >:文件基名 + 原样的抛出对象(不重新包装、不字符串化)。

为什么是 A 而不是内部 logger.warn报告是调用方的事。boot 要一条 warn,HTTP handler 要在不动 wire 形状的前提下记一行,os doctor 要的是一行 HealthCheckResult 而不是 stderr。把事实返回出去(而不是持有 logger,也不是一个默认静默的可选 onSkip 回调),才让「我只读了半个 ledger」成为类型上的事实:消费者想忽略它,必须显式写出来。

ENOENT / EACCES / Unexpected end of JSON input 是三种不同的运维事实、三种不同的修法,所以 cause 一路透传,由消费者引原话(#5390 体例)。

目录级枚举失败仍然 throw,没有被顺手「补全」成不抛 —— 那是「什么都没读到」,和「读到了一部分」是两个事实,#5412 已经把它们报成两行了。producer 侧也补了一条测试钉住这点。

三个消费者的接线

消费者 做法
rehydrate() 每个 skipped 条目一条 warn放在 entries.length === 0 提前返回之前 —— 全部条目都损坏是本 bug 的最坏情况(每个已装应用都消失),不能反而是唯一沉默的那条路径。行内含文件名、后果、原始 cause、以及要修/删的绝对路径
handleList() 同样落日志;wire 响应形状一字未动(把 skipped 放进响应体属于该端点 schema 的另一个决策,本单不做,测试里有一条断言钉住 data 的键集不变)
os doctor skipped 产出 Unique scope warning 行(复用 renderHealthCheckResult()),并抑制 ;与 #5412 的目录级行并存、各报各的

日志档位取 warn,与 rehydrate() 既有的「拿不到 manifest service」同档:按 AGENTS.md 的判据,这是功能性降级(ledger 文件仍在盘上,没有任何声称已持久化的东西没落地),系统只是可见地比 ledger 说的小一圈。

反向验证(方向先判后跑)

预判:#5414⚠ SCOPE BOUNDARY 用例会转红,且只红在 not.toContain('broken') 这一条 —— 新行的 headline 与 LEDGER_HEADLINE 是两串不同的字,所以那条断言应当仍绿。

实跑与预判一致,红在 doctor-ledger-read-failure.test.ts:349,其余 742 条全绿。doctor 真实输出:

⚠ Unique scope   1 installed-package ledger entry could not be read (those packages NOT
                 checked for installation-wide uniques) — broken.json: Expected ',' or '}'
                 after property value in JSON at position 60 (line 1 column 61)

该用例按其自身注释改写为正向断言(损坏条目 → 报告出现且指名、 不出现),并未删除 —— repro 一字未改,只是判定反了过来。

验证

pnpm --filter @objectstack/cloud-connection test    15 files / 101 tests passed
pnpm --filter @objectstack/cli test                 78 files / 745 tests passed
pnpm --filter @objectstack/cli typecheck            Done
pnpm --filter @objectstack/cloud-connection build   DTS build success(该包无 typecheck 脚本,
                                                    在 DEBT 账本内;check:type-check-coverage OK,
                                                    358 frozen errors 未变)
pnpm check:durability-log-level                     OK
pnpm check:startup-registry-verdict                 OK(40 seams,无新增)
node scripts/check-nul-bytes.mjs                    OK(另自扫改动文件的 0x00-0x1f,clean)
eslint(改动文件)                                    clean

消费者普查

仓内 list() 的生产消费者只有两处(marketplace-install-local-plugin.tsreadAlldoctor.ts),没有第 4 个cloudpackages/objectos-runtime/src/index.ts 只是再导出 LocalManifestSource,不调用 list(),不受返回类型变更影响。

changeset

@objectstack/cloud-connection minor(公开契约变更,body 里写了 FROM → TO 的一行迁移)、@objectstack/cli patch。


Generated with Claude Code


Generated by Claude Code

…edger entries it could not read (#5413)

A truncated / unreadable / unparseable file under
`.objectstack/installed-packages/` was dropped in an un-bound per-file `catch`
and `list()` returned a bare array, so a short list was indistinguishable from a
complete one: no difference in the return value, no log, no count. All three
consumers gave a confidently wrong answer — `rehydrate()` left the installed app
unregistered (gone from the app switcher, its objects nonexistent) with nothing
in the log, `handleList()` served the console a list that looked whole with
`success: true`, and `os doctor` printed a clean `✓ Unique scope` over manifests
it had never parsed.

Skipping a corrupt file stays correct — one bad manifest must not stop a runtime
booting the packages that are fine. Skipping it SILENTLY was the defect.

`list()` now returns `{ entries, skipped }` (option A of the issue's decision
point): reporting is the caller's job, and "I read only half the ledger" becomes
a fact in the type rather than an absence. Enumerating the DIRECTORY still
throws — a different fact from "some files in it would not parse", and #5412
already reports the two as separate rows.

Wiring, per triage:
- `rehydrate()` warns per skipped file, before the empty-entries early return
  (an all-corrupt ledger is the worst case, not the exempt one), naming the file,
  the consequence and the thrower's own words.
- `handleList()` logs the same; the WIRE SHAPE is deliberately unchanged —
  putting the skip in the response body is a separate schema decision.
- `os doctor` turns `skipped` into a `Unique scope` warning row and withholds
  the `✓` success line, alongside the directory-level row from #5412.

#5414's `⚠ SCOPE BOUNDARY` test went red exactly as its own comment predicted
and is rewritten as the positive assertion.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016FNvXhtSdnEGEfLEsMmvxh
@vercel

vercel Bot commented Aug 5, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Aug 5, 2026 11:05am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/l labels Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/cli, @objectstack/cloud-connection.

22 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/cli)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli)
  • content/docs/automation/hook-bodies.mdx (via packages/cli)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/validating-metadata.mdx (via packages/cli)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/plugins/index.mdx (via @objectstack/cli)
  • content/docs/plugins/packages.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/metadata-service.mdx (via @objectstack/cloud-connection)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/cloud-connection)
  • content/docs/releases/v16.mdx (via @objectstack/cli)
  • content/docs/releases/v17.mdx (via @objectstack/cli)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

Copy link
Copy Markdown
Contributor Author

范围外发现(Prime Directive #10,均已另开 issue,未在本 PR 修

实施过程中在同一份文件 / 同一条报告路径上核验到两条,都落在本单的完成范围内:

两条均已按关键词 + 文件路径查重(LocalManifestSource / installed-packages / ledger / manifest cache / doctor + posture),无重复;唯一命中是 #5413 自身。


Generated by Claude Code

@baozhoutao
baozhoutao marked this pull request as ready for review August 5, 2026 11:11
@baozhoutao
baozhoutao added this pull request to the merge queue Aug 5, 2026
Merged via the queue into main with commit 7127b48 Aug 5, 2026
24 checks passed
@baozhoutao
baozhoutao deleted the claude/issue-5413-manifest-source-skipped-entries branch August 5, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants