Skip to content

fix(seed-loader): report deferred reference back-fill failures instead of swallowing them (#2805)#3219

Merged
os-zhuang merged 1 commit into
mainfrom
claude/delayed-reference-update-failure-aquqs0
Jul 18, 2026
Merged

fix(seed-loader): report deferred reference back-fill failures instead of swallowing them (#2805)#3219
os-zhuang merged 1 commit into
mainfrom
claude/delayed-reference-update-failure-aquqs0

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Summary

Fixes #2805.

A circular reference between two seed records is resolved in two passes: the parent is inserted first without the back-reference (deferred to pass 2), then pass 2 issues an engine.update to fill the reference in once the target exists.

If that pass-2 back-fill threw, resolveDeferredUpdates only logged a warning — the reference stayed NULL, yet the load still returned success: true, errors: [], totalErrored: 0. An incomplete relationship was reported as a clean load.

Repro (issue scenario)

audit_department.head_id → audit_worker and audit_worker.department_id → audit_department reference each other. Engineering inserts first (its head_id → Alice is deferred); Alice inserts next; pass 2 back-fills Engineering.head_id via engine.update. When that update fails, the link is never written but the loader reported success.

Fix

Route both pass-2 failure modes — target still missing, or the back-fill write threw — through a single recordDeferredError helper that:

  • pushes a ReferenceResolutionError into the object's per-result errors,
  • bumps its errored count so summary.totalErrored is truthful, and
  • joins allErrors so the load reports success: false.

This matches how pass 1's update path already reports write failures, and closes the latent gap where the "still unresolved after pass 2" branch recorded an error but never bumped errored.

Scope note

A lone transient blip on the back-fill still recovers via withTransientRetry (the issue's literal one-shot "fetch failed" repro under-specifies this — a single transient error is retried and succeeds). Only a failure that outlasts the retry budget, or a non-transient error, is now reported. Both behaviors are pinned by tests.

Tests

New seed-loader-deferred-failure.test.ts:

  • a persistently-failing pass-2 back-fill → success: false, totalErrored > 0, head_id left NULL, error names the head_id field (this test fails on main, passes with the fix);
  • a transient blip that recovers on retry → still clean success: true, totalErrored: 0.

Existing seed-loader-replay.test.ts and seed-loader-retry.test.ts continue to pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MAg2Tzkv69j9zx6ZyyrbHC


Generated by Claude Code

…d of swallowing them (#2805)

A circular reference between two seed records is resolved in two passes: the
parent is inserted first without the back-reference (deferred), then pass 2
issues an engine.update to fill it in. If that pass-2 update threw,
resolveDeferredUpdates only logged a warning — the reference stayed NULL yet
the load still returned success: true, errors: [], totalErrored: 0. An
incomplete relationship was reported as a clean load.

Route both pass-2 failure modes (target still missing, or the back-fill write
threw) through a single recordDeferredError helper that pushes a
ReferenceResolutionError into the object's per-result errors, bumps its
errored count so summary.totalErrored is truthful, and joins allErrors so the
load reports success: false — matching how pass 1's update path already
reports write failures.

Note: a lone transient blip on the back-fill still recovers via
withTransientRetry (covered by a test); only a failure that outlasts the
retry budget — or a non-transient error — is reported.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MAg2Tzkv69j9zx6ZyyrbHC
@vercel

vercel Bot commented Jul 18, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 18, 2026 2:30pm

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/metadata-protocol.

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

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol)

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.

@os-zhuang
os-zhuang marked this pull request as ready for review July 18, 2026 14:32
@os-zhuang
os-zhuang merged commit b7940da into main Jul 18, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/delayed-reference-update-failure-aquqs0 branch July 18, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(种子):延迟引用更新失败可能导致关系不完整,但报告却显示成功

2 participants