fix(metadata-protocol): 引用解析不了而整条丢弃的 seed 记录,现在会在 error 级别说出来 (#4997) - #5128
Merged
Merged
Conversation
…le reference at `error` (#4997) The pass-1 branch that drops a WHOLE record — reference unresolvable and no pass 2 to fix it — counted the loss (`errored`), reported it (`result.errors` → `success: false`) and its own comment claimed "LOUD", but it made no logger call at all. A seed that dropped N records printed exactly what a clean one printed, and the `packages/runtime` seed call sites that only `await` the load never read `result.success`. It now logs at `error` per AGENTS.md → "Degradation log levels" (#4632), naming the consequence (record #i of <object> was not seeded AT ALL, not just its association) and all three remedies (seed the target first, enable `multiPass` so pass 2 back-fills, or fix the natural key in the seed data). Applying the same objective criterion — does the outcome enter `errors`/`allErrors`? — to the rest of the file found one more branch with a count and no log: "deferred reference unresolved after pass 2", whose sibling (back-fill write failed) has logged at `error` since #4729. Aligned. The dry-run branch stays QUIET by decision, with the reason in a comment and a test pinning it: a dry run writes nothing, its caller is reading the result object by definition, and an `error` about a simulated outcome trains readers to skim `error`. No counters, result shapes or `result.errors` messages changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NrmBxj8rK2uGCnh9aipjwX
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 3 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
This was referenced Aug 4, 2026
Closed
xuyushun441-sys
marked this pull request as ready for review
August 4, 2026 06:35
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 #4997
问题
packages/metadata-protocol/src/seed-loader.tspass-1 的引用解析分支:引用解析不了、且multiPass关闭(没有 pass 2 来补救)时,整条记录被丢弃 —— 这是正确的取舍(写下去要么把原始自然键塞进 FK 列,要么在 upsert UPDATE 路径上污染已有行)。丢弃被计数(errored)、被上报(result.errors→success: false),分支自己的注释还写着 "LOUD",但这里没有任何 logger 调用。结果就是:一次丢了 N 条记录的 seed,与一次干净的 seed 在控制台上一模一样。唯一的区别是调用方有没有去看
result.success—— 而packages/runtime的若干 seed 调用点只是await之后继续。#4729 盘的是本文件的
this.logger.warn调用,所以看不到这一格;check:durability-log-level只扫try/catch,这里不是 catch,也扫不到。改动
1)pass-1 丢弃分支补
error日志(按 AGENTS.md →「Degradation log levels」/ #4632 的两项义务)一行里同时给出后果与修复动作:
三条补救路径就是 issue 列的三条:先种目标对象 / 打开
multiPass让 pass 2 回填 / 修掉 seed 里的自然键。注释里那句名不副实的 "LOUD: counted + reported" 也改写成现在真实成立的说法(计数 + 上报 + 日志三者齐了)。2)dry-run 分支:维持安静,并把理由写进注释 + 用测试钉住
dry-run 什么都不写,没有任何损失;它的调用方按定义就是来读结果对象的(
validate()的全部意义)。为一次模拟结果打error,正是 AGENTS.md 警告的过度施加 —— 训练读者跳过error,而这恰恰是 #4420 那条warn没人读的成因。所以它保持安静,但这是一个决定而不是疏忽,因此有测试钉住:往这个分支加日志会立刻变红。3)同一客观判据扫完本文件,顺手对齐了另一处
判据是 #5001 那一条:这个结局有没有进
errors/allErrors? 全文件只剩一处「进了、却一行日志都没有」——resolveDeferredUpdates()里的 "deferred reference unresolved after pass 2"(目标始终没出现)。它的孪生分支(回填 写失败)从 #4729 起就在error上报,而它计数完全相同、日志为零。现在也补上:说清行本身已经种下、关系永久缺失、以及怎么补齐。测试
新增
packages/metadata-protocol/src/seed-loader-unresolved-drop.test.ts(5 例):error日志点名 object / record #i / field / target 与三条补救;并且仍然被计数(totalErrored: 1、success: false、行计数仍与total对账、referencesDropped保持 0 —— 丢的是记录不是字段);error);[dry-run] Reference may not resolve的完整说明,engine.insert一次没调,控制台安静;error日志 + 已有计数。变异钉(mutation pin),三处都验过:
logger.errorexpected "vi.fn()" to be called 1 times, but got 0 times→ 红logger.errorlogger.errorexpected "vi.fn()" to not be called at all, but actually been called 1 times→ 红跑过的命令(均在
flock /tmp/os-heavy-verify.lock下,NODE_OPTIONS=--max-old-space-size=4096,--maxWorkers=2):pnpm --filter @objectstack/metadata-protocol test→ 37 files / 324 tests passedpnpm --filter @objectstack/runtime exec vitest run src/seed-loader.test.ts(下游消费方)→ 41 passedtsc --noEmit(本包在 [P2] framework: 66 个包用 tsup 构建、无人做类型检查 —— 实测 18 个包共 380 处 code-tier 错误(#4118 的 framework 侧对应) #4311 的 DEBT 账本里,无typecheck脚本):改动前后同为 62 条,新增 0 —— 新测试文件按 nodenext 用./seed-loader.js导入,不给账本添噪check:durability-log-level、check:startup-registry-verdict、check:type-check-coverage、check:engine-double-contract(13 pinned / 31 DEBT / 1 exempt,加文件前后一致)、check:published-files、check:nul-bytes、check:doc-authoring、check:error-code-casing、check:role-word、check:adr-anchors、check:release-notes、check:merge-driver、check:docs-audit-scope、check:node-version、check:driver-conformance、check:wildcard-fallthrough、check:init-service-contract、check:route-envelope、check:service-providers、check:slot-lookup、check:authz-resolver、check:org-identifier、check:stall-guard、check:console-sha、check:objectui-changeset全绿;eslint干净git stash -u后复跑同样失败):check:objectui-pin-fresh(objectui pin 过期)、check:i18n/check:i18n-coverage(本 worktree 未全量 build)范围
只动
seed-loader.ts+ 新测试 + 一个 changeset(@objectstack/metadata-protocolpatch)。packages/spec/**与生成物零改动;protocol.ts(#5088 在飞)零改动;content/docs/releases/未触碰。计数、结果对象形状、result.errors里的 message 一律未变 —— 补的是本该有却没有的控制台输出,不是契约变更。顺带发现(已另开 issue,未在本 PR 修)
insertedRecords里找不到(if (recordId)没有else),这条 deferred 回填既不计数也不打日志,只在结果对象里留下一个永远挂账的referencesDeferred。它连计数都没有,不在本 issue 的判据内,故单开。check:durability-log-level只扫try/catch,看不到这一类「非 catch 的静默丢弃」。按 fix(seed-loader): roll-up summary 重算耗尽重试后改记 error 并计入结果对象 (#4998) #5062 刚返修过该脚本、同文件避免连续改动的纪律,本 PR 不动它。是否值得为这一形态单开一个扫描器,我的判断是值得,但要单开 issue 单独讨论:它需要的判据(「一个分支写了errors/allErrors却没有 logger 调用」)是可 AST 化的,而且这轮两条发现都出自人工盘点,说明这个形态会复发;但它的假阳性面比 catch 大得多(dry-run 这类「安静是正确答案」的分支必须先有基线/豁免机制),所以不适合作为本 PR 的搭车项。Generated by Claude Code