Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

The "Used by" panel collapses every references() failure into "Safe to delete" — a server error is rendered as a measured empty result #5110

Closed

Description

@os-zhuang

Found while implementing objectstack#9326 (objectstack PR #9425), which fixes the producer half of this in @objectstack/rest. Filed separately because the fix lands here, in objectui.

The measurement

packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx — the References tab loader (around line 793; locate it by text, not by line number):

setRefsLoading(true);
try {
  const r = await client.references(type, name);
  setRefs(r);
} catch (err) {
  setRefs([]);
  console.error('references() failed', err);
} finally {
  setRefsLoading(false);
}

setRefs([]) is the same state a successful call returning zero references produces. And ReferencesPanel renders that state as, verbatim from metadata-admin/i18n.ts:

'engine.edit.refsEmptyDesc': 'Nothing in the metadata graph points at this item. Safe to delete.'

So any failure — the server refused, the network dropped, the session expired, the response was unparseable — is shown to the operator as an affirmative, measured statement that nothing depends on this item, and that deleting it is safe. The only trace is a console.error nobody is looking at. The user is typically on this panel because they are about to delete something.

MetadataClient.references() (packages/data-objectstack/src/metadata-client.ts) does its half correctly: it returns [] only for a 404, and throws parseError(res) for every other non-ok status. The information reaches this component intact and is discarded here.

Why now

@objectstack/rest used to answer 200 {references: []} when the resolved protocol had no findReferencesToMeta method — a capability gap rendered as "nothing depends on this item". objectstack#9326 / PR #9425 changes that branch to refuse:

501  { error: { code: 'NOT_IMPLEMENTED', message: '...' } }

That makes the wire honest. It does not by itself remove the user-visible harm, because this catch turns the truthful 501 straight back into "Safe to delete." The producer fix is necessary and not sufficient; this is the other half.

Not blocked by it, though. The catch swallows failures today, for every cause listed above, and can be fixed independently of what the server sends.

What would close it

An error state distinct from the empty state. Note that the current shape has no room for one: ReferencesPanel reads refs == null as still loading —

if (loading || refs == null) return <spinner/>;
if (refs.length === 0) return <Empty>…Safe to delete…</Empty>;

— so simply not setting refs on failure leaves a permanent spinner, and setRefs([]) is the lie. A third state is needed (an error field, or a discriminated union for the panel's data), plus copy for it. Suggested shape, not asserted: the panel says the check could not be completed and offers a retry, and deliberately says nothing about whether deletion is safe — the honest answer when the question was not answered.

⚠️ Worth checking while in there whether the same catch → empty pattern appears on the sibling tabs this page loads (history, audit, diagnostics). A zero there needs its own control query before it is reported as a zero.

Related

objectstack#9326 / objectstack PR #9425 (the producer half — the REST route now refuses instead of answering empty) · objectstack#9426 (the same producer-side defect class on the audit route) · ADR-0110 D3, "a miss and a fault are different facts"

Dedup

Searched open issues here for the references panel, the "Safe to delete" empty state, and ResourceEditPage error handling; nothing covering this. Control query on the same repo (metadata admin resource edit page) returned three real, related cards (#4308, #4518, #4132, all closed), so the zero above is a measurement rather than a broken search. No duplicate.

Activity

  1. added theissue type on Aug 18, 2026
  2. os-zhuang commented on Aug 18, 2026

    @os-zhuang
    ContributorAuthor

    Triage: pm:queue, type Bug (lands in packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx + ReferencesPanel + metadata-admin/i18n.ts). Rationale: a failed safety check rendered as an affirmative "Safe to delete" is a user-reachable harm today, independent of the producer fix (objectstack PR #9425 makes the wire honest; this catch converts the honest 501 back into the lie). Dispatch notes: the third state (error ≠ empty ≠ loading) is required — the panel's refs == null overload means "just don't set it" is a permanent spinner; error copy asserts nothing about deletion safety and offers retry. The sibling-tab sweep (history/audit/diagnostics catch → empty) is in scope as measurement with control queries — siblings found there are findings to file, not riders. New i18n keys follow the repo's zh-table/lock discipline. Not blocked by the producer PR.

    Triage seat routine — session session_pm_triage_20260818T0104Z (closing brief on objectstack#6015).


    Generated by Claude Code

  3. self-assigned this
    on Aug 18, 2026
  4. yinlianghui commented on Aug 18, 2026

    @yinlianghui
    Contributor

    认领(objectui 分片 PM,session session_01GTRjn8xBqp75dk7kFupVRt,批次 23):派 os-dev 席位实施,分支 claude/issue-5110-references-error-state。

    执行口径(承接分诊评论 5322192245,PM 采信全部四条派发注记):

    • 第三态是硬要求:refs == null 已被 loading 复用,失败「不 set」= 永久 spinner,setRefs([]) = 谎报安全 —— 需要 error ≠ empty ≠ loading 的判别态(error 字段或 discriminated union,形状由席位按面板现状定)。
    • 错误态文案对删除安全性零断言 + 提供 retry —— 「问题没被回答」的诚实答案,不说 safe 也不说 unsafe。
    • 兄弟 tab 普查(history/audit/diagnostics 的 catch → empty 同形)是测量不是修复:命中开 finding 卡(不 assign),⛔ 不夹带进本 PR;零命中要带对照查询。
    • 新 i18n key 走仓内 zh 表/lock 纪律。
    • 半径:ResourceEditPage.tsx References tab loader + ReferencesPanel + metadata-admin/i18n.ts + 测试与 changeset。与在飞席位(plugin-view/ObjectView.tsx、scripts/ alias 门、plugin-map.mdx)零重叠。

    Generated by Claude Code

  5. yinlianghui commented on Aug 18, 2026

    @yinlianghui
    Contributor

    PM 交接(条件释放)(session session_01GTRjn8xBqp75dk7kFupVRt,2026-08-18):维护者指示本 PM 会话下班收工。本卡执行席位派发于本会话,收工时仍在实施中(分支 claude/issue-5110-references-error-state 尚未 push、未开 PR)。处置条款:

    1. 若稍后出现该分支的 draft PR(席位可能在会话容器回收前完成推送):任一 PM 可按认领评论 5325396476 的执行口径直接做标准验收(实物核验 + CI 亲读终态 + 验收评论/undraft/auto-merge 三件套)。
    2. 若无 draft PR 出现:本认领即告释放,本卡回到可认领态;重认领者先查远端有无同名分支的部分推送,可复用或重置。
    3. 执行口径与 PM 代裁以认领评论为准,不随会话结束失效。

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingpm:queue

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions