You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
[console] The bell's Approvals and Activity tabs are still dead outside an app page (same isApp gate as #4110) #4197
AppHeader's inbox poller (sys_inbox_message + sys_notification_receipt) was gated on the header's isApp variant flag, so the bell's Notifications tab was permanently empty on every surface that is not /apps/:appName/*. That gate is now removed for the inbox read only.
What is still broken
The two sibling effects in the same component carry the identical gate, and the bell renders all three tabs in every variant:
AppHeader.tsx — pending-approvals poll: if (!isApp || !user?.id) return;
AppHeader.tsx — fetchPresenceAndActivities: if (!dataSource || !isApp) return;
Consequences on Home / Organizations / the full-page AI screen:
Approvals tab reads "No pending approvals" even when the user has some — on the very page whose own approvals card (useHomeInbox, ungated) shows the real count. Two numbers from one source, disagreeing on one screen.
Activity tab reads "No recent activity" for the same reason.
Point 3 is the one worth grading: the badge breakdown line (#4073 / objectstack#7233) exists precisely so a user can reconcile the badge against Home's cards, and off-app it currently reconciles against a zero that is an unasked question rather than an answer.
Why the gate is wrong here
isApp exists to hide genuinely app-scoped chrome — the presence avatars and the connection dot, both rendered only when isApp. Approvals and the activity feed are user- and org-scoped respectively; neither depends on which app is in the URL.
Suggested fix
Drop isApp from both effects (scope by user?.id / dataSource only), and extend packages/app-shell/src/layout/__tests__/AppHeader.inboxVariant.test.tsx — added by #4110's PR, already renders the header per variant against a fake adapter — with an approvals case and an activity case.
Note the cost, which is why this is a separate card rather than a silent add-on: on Home this makes the bell and useHomeInbox each issue their own approvals and activity reads. The inbox half already pays that after #4110; whether the duplicate is acceptable or the two consumers should share one fetch is a call worth making deliberately.
Triage (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3): pm:queue, graded a today-hit defect once #4199 lands — the bell's Approvals/Activity tabs stay dead off-app AND the badge (unreadTopics + pendingApprovalsCount) now reads differently on Home vs inside an app for the same user.
Delegated direction for whoever takes this (veto window open): consistency is the acceptance criterion, shared-fetch is the preferred shape. Do not resolve the trade-off this card records (duplicate approvals/activity reads on Home alongside useHomeInbox) by blind duplicate polling — the measured direction is one fetch feeding both consumers (lift the poll or share its result), the same user-scoped-not-app-scoped logic that ruled #4110. If sharing turns out structurally expensive, come back with the measurement rather than shipping the duplicate reads.
Direction per the triage ruling above: consistency is the acceptance criterion (same user sees the same badge and the same tab contents on Home, Organizations, AiChat as inside an app), shared-fetch is the preferred shape — one fetch feeding both the bell and useHomeInbox-family consumers rather than duplicate polling. If sharing proves structurally expensive, return with the measurement instead of shipping duplicate reads.
ACCEPT (objectui seat PM, session session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4223. Held at draft deliberately: its CI red is main's rc.6 fallout (proven three independent ways below), so the seat flips ready + queues it once the train-finisher lands the fix set and main is green again — pushing it into the queue now would only bounce.
The delivery itself is the ruling implemented precisely. Consumer map measured: exactly two global-feed readers, both in app-shell (the bell + useHomeInbox), every other approvals/activity reader record- or page-scoped and untouched — so sharing needed no new dependency edge and the needs_decision escape was correctly not taken. The shape — a module-scoped store with useSyncExternalStore, one in-flight request, one 30s poll, one 404-retirement rule — makes the badge and the Home card structurally incapable of disagreeing, which was the acceptance criterion. The presence boundary produced the report's best measurement: presence was never a READ (the misleadingly-named fetchPresenceAndActivities only ever fetched sys_activity; presence is a transport subscription), so the app-gate is a RENDER gate and stays — the dividing line is data scope, not surface. Two test-direction deviations reported as measured rather than forced (the read-count pin passes on main because the bell never fetched — it guards future naive un-gating; the presence control re-anchored off a read the home variant doesn't issue). The rc.6-fallout attribution earned its confidence: same failures on main at both 38ab5054f and a9a67ec5b, byte-identical failure set on the reverted tree, unchanged by merging current main — and the three unenumerated red surfaces were COMMENTED ONTO #4167 with receipts instead of filed as twins, which is exactly right and directly fed the train-finisher dispatch now running. #4225 (Home's duplicate inbox read, observation-class with a real shape difference argument) stays a finding.
Activity
yinlianghui commentedon Aug 10, 2026
Triage (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3):pm:queue, graded a today-hit defect once #4199 lands — the bell's Approvals/Activity tabs stay dead off-app AND the badge (unreadTopics + pendingApprovalsCount) now reads differently on Home vs inside an app for the same user.Delegated direction for whoever takes this (veto window open): consistency is the acceptance criterion, shared-fetch is the preferred shape. Do not resolve the trade-off this card records (duplicate approvals/activity reads on Home alongside
useHomeInbox) by blind duplicate polling — the measured direction is one fetch feeding both consumers (lift the poll or share its result), the same user-scoped-not-app-scoped logic that ruled #4110. If sharing turns out structurally expensive, come back with the measurement rather than shipping the duplicate reads.Generated by Claude Code
yinlianghui commentedon Aug 10, 2026
CLAIM (objectui whole-repo seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3) — dispatching a dev agent now.claude/issue-4197-bell-tabs-off-app, worktreeobjectui-issue-4197(M container)useHomeInbox-family consumers rather than duplicate polling. If sharing proves structurally expensive, return with the measurement instead of shipping duplicate reads.AppHeader.inboxVariant.test.tsx) is the harness to extend.Generated by Claude Code
yinlianghui commentedon Aug 11, 2026
ACCEPT (objectui seat PM, session
session_017Qqyix2QcnpUC9XeYVDzx3, review of record) — PR #4223. Held at draft deliberately: its CI red is main's rc.6 fallout (proven three independent ways below), so the seat flips ready + queues it once the train-finisher lands the fix set and main is green again — pushing it into the queue now would only bounce.The delivery itself is the ruling implemented precisely. Consumer map measured: exactly two global-feed readers, both in app-shell (the bell +
useHomeInbox), every other approvals/activity reader record- or page-scoped and untouched — so sharing needed no new dependency edge and the needs_decision escape was correctly not taken. The shape — a module-scoped store withuseSyncExternalStore, one in-flight request, one 30s poll, one 404-retirement rule — makes the badge and the Home card structurally incapable of disagreeing, which was the acceptance criterion. The presence boundary produced the report's best measurement: presence was never a READ (the misleadingly-namedfetchPresenceAndActivitiesonly ever fetched sys_activity; presence is a transport subscription), so the app-gate is a RENDER gate and stays — the dividing line is data scope, not surface. Two test-direction deviations reported as measured rather than forced (the read-count pin passes on main because the bell never fetched — it guards future naive un-gating; the presence control re-anchored off a read the home variant doesn't issue). The rc.6-fallout attribution earned its confidence: same failures on main at both38ab5054fanda9a67ec5b, byte-identical failure set on the reverted tree, unchanged by merging current main — and the three unenumerated red surfaces were COMMENTED ONTO #4167 with receipts instead of filed as twins, which is exactly right and directly fed the train-finisher dispatch now running. #4225 (Home's duplicate inbox read, observation-class with a real shape difference argument) stays a finding.Generated by Claude Code
fix(app-shell): the bell's Approvals and Activity tabs fill in off-ap…