Repository navigation
The console HOME header renders a second, different inbox polling the wrong source — sys_inbox_message instead of /api/v1/notifications, no badge, "You're all caught up" with 9 unread #4235
Copy link
Copy link
Closed
Labels
Description
Activity
CLAIM + 代决框架 — session
session_017Qqyix2QcnpUC9XeYVDzx3(objectui whole-repo PM seat;否决窗口开放)。Branch:claude/issue-4235-home-inbox-source。前情汇入:#4230 已裁定两面板 TWO 独立修,且其调查更新了本卡的两个前提——(1) 两份 QA 报告(含本卡的 9-unread-空面板与 7517 的"home 卡正常"对照)都来自过期 vendored console
09987b68(比 #4199 早 42 小时);(2)"wrong source"不是自明缺陷:铃铛读sys_inbox_message+receipts 是 ADR-0030/#1429 有意为之,本卡的源选择是设计问题。故派发形态为 premise-check-first + 带判据的两分支:- 先复现并解元矛盾:当前 main 上用 QA 形状(9 unread)驱动
useHomeInbox+HomeActionCenter,确定空面板是否可复现、由什么条件决定(user_id 作用域 / receipts 连接 / approvals 分支)——跨 run 矛盾说明存在一个条件开关,找到它比断言谁的报告过期更有价值。 - 源问题按测量分支:实测 ADR-0030/feat(app-shell): repoint Console bell to sys_inbox_message + receipts (ADR-0030) #1429 的裁决范围。(a) 若表读是消费者的 sanctioned 通道 ⇒ 保源,修"读空的条件缺陷";(b) 若
/api/v1/notifications才是消费者面 ⇒ 经sharedUserFeeds扩展 inbox feed 改道(Home readssys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query #4225 建议的路线),铃铛不动、test(app-shell): pin the bell panel's Unread/All render oracle — #4230's console predates #4199 (#4230) #4284 新落的绊线套件必须原样绿。证据真模糊 ⇒ needs_decision 报告,不写码。 - 无条件裁决,两分支都钉:肯定语气的"You're all caught up"只允许出现在成功且为空的应答后;读取失败/未认证/未知态一律不得渲染它(Post-login landing ignores
isDefault— cold sign-in always lands on/_console/home(and AppManagementPage's Disable / Set-as-default are client-only stubs) #4233 的"错误≠空"原则同型)。
Surface:
app-shellhooks(useHomeInbox、sharedUserFeeds)+ console/home 组件;与在飞 #4265(useObjectActions/ActionConfirmDialog)同包不同文件,互斥令写入派单。#4225 双向警告(改共享 feed 不得重破铃铛)与 #4289(404 闩锁 finding)一并交给 dev 作地图。
Generated by Claude Code
- 先复现并解元矛盾:当前 main 上用 QA 形状(9 unread)驱动
ACCEPT — PM review of record (session
session_017Qqyix2QcnpUC9XeYVDzx3)。PR #4315 验收要点:
- 元矛盾解开且证据链完整:翻转条件是登录者的权限集——同一 console pin 下 admin 读
sys_inbox_message正常(objectstack#7517 的"working control"),普通成员按 objectstack#7344 的浏览器实测吃 403(shipped 权限集无人授该表),useHomeInbox的裸.catch(() => {})把拒绝穿成空收件箱 ⇒ "all caught up + 无徽标 + 9 未读"。两份 QA 报告都是真的,只是不同 persona。403 本因已被今日维护者裁决(Option A,objectstack#7586 已合)关闭;本 PR 关闭的是 console 侧把任何失败转译成好消息的通道。 - ADR-0030 判定:表读 sanctioned,branch (a) 正确——三处 ADR 原文 +
/api/v1/notifications即同表投影的服务端测量 + 迁移替代方案今天刚被上游裁决否掉(选了授权而非改道)。改道会与当日裁决相抵,保源修条件是唯一对的方向。 - 无条件裁决落地:肯定文案门在
notificationsStatus === 'ready',状态词直接复用 MetadataProvider 的四词方言(fix(console): an unloadable app list is UNKNOWN, not "no default app"; wire the Applications page's writes (#4233) #4300 的 one-dialect 裁决,零新方言);approvals 半场单独应答时面板不静默丢弃失败半场。404 保持"是答案"的裁量有据(社区构建无 messaging 服务不该常驻错误行)且双极性钉住。 - 边界纪律全守:bell/InboxPopover/sharedUserFeeds 零改动,test(app-shell): pin the bell panel's Unread/All render oracle — #4230's console predates #4199 (#4230) #4284 绊线套件在全包运行中原样绿;无新 i18n 键(避开 [P2] objectui: every package type-checks its tests or declares why not — and guards must prove they can fail (measured: 355 errors across 19 packages) #4040-t2 的持有面)。反向验证 4/5 精确,两个非判别绿如实声明。CI 20 项收敛。
连带处置:
- Home's action centre counts ALREADY-READ messages as needing attention —
useHomeInboxnever joinssys_notification_receipt#4316 定级 bug 入队——镜像缺陷(已读消息仍算"需要你关注":无 receipt 连接,假阳性 vs 本卡的假阴性),修复路径归 Home readssys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query #4225 的共享 inbox feed。 - Home reads
sys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query #4225 依证据重定级:其 observation 前提("两个消费者都正确、无分歧")已被 Home's action centre counts ALREADY-READ messages as needing attention —useHomeInboxnever joinssys_notification_receipt#4316 证伪——升pm:queue并立即派发为共享 inbox feed 卡(见该卡评论);isMissingResource×3 副本的合并作为其 rider。
Generated by Claude Code
- 元矛盾解开且证据链完整:翻转条件是登录者的权限集——同一 console pin 下 admin 读
- added a commit that references this issue
on Aug 11, 2026
Symptom
The console home header renders an inbox panel that disagrees with the notifications API.
sys_inbox_messageinstead of/api/v1/notifications./api/v1/notifications(or at minimum agrees with it), shows an unread badge, and does not claim an empty inbox while 9 unread rows exist.#4230 (open,
bug+pm:queue) covers the top-bar bell panel — "No notifications" under both Unread and All while/api/v1/notificationsreturns 10 rows — itself filed as a regression of #4110 (closed completed by PR #4199) and #4156 (closed as duplicate).These are two distinct panels with the same class of bug — a consumer reading the raw inbox tables instead of
/api/v1/notifications, and disagreeing with it. A fix to one does NOT fix the other. They are separate components with separate reads: the bell's poll lives inpackages/app-shell/src/layout/AppHeader.tsxand renders throughpackages/app-shell/src/layout/InboxPopover.tsx; the panel reported here is on the Home surface and is fed bypackages/app-shell/src/hooks/useHomeInbox.ts. #4230 itself flags this second panel as "a distinct surface … Worth deciding whether they are one fix or two" — this card is the answer to that question: two panels, filed separately, cross-linked.Treat the closed prior art as weak evidence of a fix: #4156 was closed as "duplicate" and #4110 as "completed" via #4199, yet #4230 demonstrates the bell symptom back on console
09987b68. This repo has a demonstrated pattern of defects closed as duplicate that were never actually fixed.Should this be folded into #4225 instead? — No
#4225 (open,
finding) — "Home readssys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query" — is adjacent and on the same code path, but it is not the same defect:sys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query #4225 is explicitly observation-class, not a defect: its own body states "Both consumers show correct data today. Nothing is stale, nothing disagrees." Its cost is one redundant round trip plus an overlapping 10s poll.Deduplicating two reads (#4225) would not make either read correct, and making this panel read the right source would not by itself remove the duplication. They should be sequenced, not merged: #4225's suggested route is to extend
hooks/sharedUserFeeds.tswith an inbox feed and have Home derive its rows from it — whoever does that will be editing exactly the hook this card indicts, so the fixer should land the source correction and the shared-feed refactor with awareness of each other, and #4225's warning applies in both directions (a shared-feed refactor must not re-break the bell, per #4230).Root cause
Located to the Home inbox read, not to the bell:
packages/app-shell/src/hooks/useHomeInbox.ts— the Home surface's inbox read. It queries the object store directly (sys_inbox_messagefiltered byuser_id, ordered bycreated_at desc,$top: limitdefault 5, plussys_activityand an approvals count) and never touches/api/v1/notifications. Its own header comment states the query shapes "mirror AppHeader so the two never diverge" — that mirroring is of the bell's raw-table read, which is the same wrong source REGRESSION: the console header bell panel is dead again — "No notifications" under both Unread and All while/api/v1/notificationsreturns 10 rows (#4110 / #4156 back on console 09987b68) #4230 is about.packages/app-shell/src/console/home/HomeRail.tsx—HomeActionCenteris the panel that renderst('home.actionCenter.empty', ...)= "You're all caught up" (~line 117) wheneverpendingApprovalsCount + notifications.length === 0, and itsCardrenders the count badge only whencount > 0— which is exactly the observed "no badge + all caught up" pair when the underlying read comes back empty.packages/app-shell/src/console/home/HomePage.tsxwires them:const { pendingApprovalsCount, notifications, activities } = useHomeInbox();feedingHomeActionCenter.Two caveats for whoever picks this up, recorded rather than smoothed over:
origin/mainfor the exact copy, badge behaviour and data source observed. Confirm the surface before editing./api/v1/notificationsreturns 10 rows (#4110 / #4156 back on console 09987b68) #4230 (from QA run QA run · approvals (FULL area) · a86db175 · 2026-08-11 · 5 PASS / 2 PARTIAL / 1 FAIL objectstack#7517, same console09987b68) records that the home page's "Needs your attention" card did surface the notifications — it was used there as the working control against the dead bell. This run (QA run · platform-core (FULL area) · a86db175 · 2026-08-11 · 3 PASS / 1 PARTIAL / 7 FAIL objectstack#7514) records the home panel as empty with 9 unread. Both cannot be unconditionally true, so there is a condition that decides it (which rows exist,user_idscoping, the approvals-count branch, or a genuinely different panel). Reproduce before assuming either report is stale.Verified still on the wrong source on objectui
origin/main@bb68488(current at filing time), not only on the vendored console09987b68the run used:useHomeInboxstill readssys_inbox_messagedirectly and issues no/api/v1/notificationscall.Reproduction
Framework
a86db175, vendored console09987b68, showcase app, authenticated session with delivered notifications.Observed: the panel polls
sys_inbox_message(no/api/v1/notificationsrequest), renders no badge, and states "You're all caught up" while 9 unread exist.Related
/api/v1/notificationsreturns 10 rows (#4110 / #4156 back on console 09987b68) #4230 — the bell panel, same bug class, different panel. Cross-linked, not duplicated.sys_inbox_messagetwice — the bell's poll anduseHomeInboxeach issue their own query #4225 — the doublesys_inbox_messageread on Home; same code path, different (observation-class) problem. Sequence with this card; do not merge.Source
Extracted from the QA run objectstack-ai/objectstack#7514 (framework a86db175, vendored console 09987b6). Root-cause re-verification is against objectui
origin/main@bb68488.