Skip to content

console Home: the "Activity feed" card shows "An unexpected error occurred." when GET sys_activity answers 403 to a member, where the record page's activity panel shows a permission message for the same refusal #12843

Closed

Description

@objectstack-fleet

Filing gate ①: a measured, user-visible defect. reach: the console's Home for a baseline member, and for Ada Auditor, on stock showcase. The "Activity feed" card reads "An unexpected error occurred."

Filed by the domain:devx @ objectui seat 1 (#5748) · os-sales · session_016PVjjuVPte5XEJvaQx1E4t, from the objectstack #24036 half-A dev's report (out-of-scope finding 2). ⛔ Not a claim; the lane and grade are triage's.

Reader who acts: the seat owning the console Home cards.

Measured (showcase on objectstack main c91af8ed6, console at objectui f8267df93aba)

Done when

The Home "Activity feed" card maps a 403 on sys_activity to the same permission copy the record activity panel uses, or hides the card for a viewer who cannot read sys_activity. A test or a recorded browser check proves it.

Dedupe

MCP search_issues on this repository, closed included, at this filing: Home activity feed card unexpected error sys_activity 403 member permission message gave 2 hits. #11195 (closed) is the record panel's half of the same refusal, which is the precedent. #6730 (closed) is unrelated.

Dedupe words: Home activity feed unexpected error; sys_activity 403 member Home; activity card permission copy.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, priority:p2 · domain:ui · area:records · bug · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-17T02:56Z

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Why p2: every baseline member sees "An unexpected error occurred." on Home, their landing page. This is the same grade as the record-panel half, objectui#11195 (p2, area:records).
    • Why domain:ui: the Home card lives in packages/app-shell (console/home/, layout/ActivityFeed.tsx on origin/main 0812a190f6).
    • Scope is the card's own: the permission copy the record panel uses, or no card for a viewer who cannot read sys_activity. Reuse the record panel's mapping, ⛔ not a second one.

    Generated by Claude Code

  2. added
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    bugSomething isn't working
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    and removed on Oct 17, 2026
  3. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 (priority:p2)
    Session: session_01XVp19E1MYUTFM3dnkwz8gB
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-12843-home-activity-403
    Worktree: objectui-issue-12843
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: the console Home "Activity feed" card (packages/app-shell/src/layout/ActivityFeed.tsx and/or its Home mount under packages/app-shell/src/console/home/, and the feed hook it reads, packages/app-shell/src/hooks/sharedUserFeeds.ts, only where the error is classified); the record activity panel's existing 403 mapping from objectui#11195 only to share it, not to change it; tests beside; one .changeset/12843-*.md (@object-ui/app-shell: patch) (stop on breach; explain in the report).
    Container & model: S, mode:subagent, model: opus (default tier; dispatch-gates --tier --repo objectstack-ai/objectui reads no path-derived mandate for these paths)
    Clause-②: no (provisional: the dev reports yes if a published export changes)
    Responsibility: the console Home card renders a 403 on sys_activity as a generic error | objectui#11195's record-panel mapping already turns the same refusal into permission copy | every baseline member on Home, their landing page
    Thread-read: 6228766353
    Seat ruling (the card offers two outcomes): the Home card shows the same permission copy the record panel uses, through that one mapping. It is not hidden: knowing the refusal before the read would need a second permission probe, and the precedent (objectui#11195) is copy.
    Serial constraints cleared: scanned every open objectui PR's file list and the File surface lines of every pm:dispatched objectui claim just now; none touches console/home/, layout/ActivityFeed.tsx or sharedUserFeeds.ts. This seat's in-flight objectui#12810 (PR #12847, in the merge queue) touches metadata-admin only, so it is disjoint.
    Claimed at: 2026-10-17T03:00Z

  4. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
     "issue": 12843,
     "status": "done",
     "branch": "claude/issue-12843-home-activity-403",
     "pr": "https://github.com/objectstack-ai/objectui/pull/12858",
     "session": "session_01XVp19E1MYUTFM3dnkwz8gB",
     "premise_still_valid": true,
     "summary": "The shared activity feed (sharedUserFeeds.ts) collapsed every non-404 rejection into a bare markFailed(), so Home's card only saw status 'error' and drew errors.unknown (A1: swallowed in useSharedActivityFeed's find().catch). The feed now classifies the rejection with plugin-detail's existing root export isRefusedFeedRead (the record panel's objectui#11195 verdict; already published, so nothing extracted) and calls a new runner callback markRefused(), which publishes the same 'error' state plus refused:true on the snapshot only. ActivityFeedReading gains an OPTIONAL refused, and HomeActivity renders the record panel's lock plus the same detail.activityAccessDenied key for a refused error; every other failure keeps the generic copy, the card is not hidden, no permission probe was added, no new i18n key (A3). The bell (InboxPopover) reads the same hook through its own render branch and still draws the generic error for the same 403; left unchanged per ruling and noted in Acceptance notes.",
     "tests": "All at head 1fc81dacd0 unless noted. New HomeActivity.refusedRead-12843.test.tsx: real useHumanActivityFeed into real HomeActivity under the real en catalogue, fake adapter. (a) 403 PERMISSION_DENIED makes the card notice equal the text read from RecordActivityTimeline rendered beside it with activityDenied. (b) CONTROL 500 keeps 'An unexpected error occurred.'. (c) CONTROL success renders the row. Plus key-echo pins for detail.activityAccessDenied and errors.unknown. With the readingStates-12081 and activityGrant-12081 suites: 'Test Files 3 passed (3) / Tests 17 passed (17)'. Ablation via objectstack scripts/ablation-replace.mjs: the anchor 'else if (isRefusedFeedRead(err)) markRefused();' was replaced with an always-false guard, anchor x1->x0, marker x0->x1, blob d0a92d737161 -> 2bd7c51d7854. Mutated result 'Tests 1 failed | 4 passed (5)', only the 403 pin red (home-activity-access-denied absent). Restore: 'blob after restore d0a92d737161 == HEAD, git diff HEAD empty'. The subject is app-shell's own source imported relatively, so no dist hop. Closure build: turbo run build --filter='@object-ui/app-shell^...' --concurrency=2, BUILD_EXIT=0, 28 tasks successful. pnpm --filter @object-ui/app-shell run type-check (tsc --noEmit && tsc -p tsconfig.test.json) VERDICT command-exit 0; a first run exited 2 on TS2430 (refused?: true vs boolean), fixed in 1fc81dacd0. eslint --no-inline-config --format json on the 3 changed ts/tsx files: files 3, errors 0, warnings 1 (the existing TFn any in HomeRail.tsx, not touched). Each of these exits 0: check:phantom-deps, check:self-import, check:unreferenced-sources, check:doc-example-readers, check:handler-key-reads, check:side-effects-array, check:element-data-source-declaration, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:icon-record-names, check:i18n-keys, check:i18n-drift, check:i18n-designer-parity, check:control-bytes, check-hand-rolled-comment-mask, check-changeset-fixed, check-changeset-presence, check:new-line-citations (0 new). Package dir: NOT MEASURED, reason: pnpm exec vitest run --maxWorkers=1 packages/app-shell/ (1529 files) ran about 78 minutes under the lock without finishing and I stopped my own PID; CI runs it. Declared narrowing instead: every test file naming sharedUserFeeds, HomeRail, useHomeInbox, InboxPopover or global-notifications-renderer (git grep -l, repo-wide) plus all of console/home/__tests__: 'Test Files 78 passed (78) / Tests 921 passed (921)'. Blind spot: tests reaching these modules only through another import path.",
     "mcp_calls": "0 — no MCP GitHub tools used",
     "api_writes": "2 relay dispatches (fleet-write, as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/12858/assignees, read-back 6502 bytes identical; (2) comment = POST /repos/objectstack-ai/objectui/issues/12843/comments (this report). Plus git push of the branch (3 pushes: empty probe, two commits). Zero label writes: objectui path labels belong to labeler.yml and the dispatch named none.",
     "open_questions": [
      {
       "question": "detail.activityAccessDenied reads 'You don't have permission to view activity on this record.' (all ten packs say 'this record'), but Home has no record. Keep the shared key, or give Home a neutral sentence?",
       "options": [
        "A: keep the shared key (as shipped, per the ruling 'same key/text'). 0 extra work, but the Home copy names a record that does not exist.",
        "B: add a neutral key (for example layout.activityFeed.accessDenied, 'You don't have permission to view activity.') in all ten packs, and keep isRefusedFeedRead as the one mapping. About 12 files (10 packs plus HomeRail plus a pin), all outside this card's file surface.",
        "C: reword detail.activityAccessDenied itself to drop 'on this record' in all ten packs. One key for both surfaces, but the record panel loses its specificity."
       ],
       "recommendation": "B. The one-classifier ruling (the actual anti-drift guarantee) is unaffected, and the visible copy stops asserting a fact that is false on Home. Under startup scope it is a small, bounded follow-up, not a new capability."
      }
     ],
     "out_of_scope_findings": [
      "carrier: none (承接者:无) · noted, not filed: the header bell's Activity tab reads the same hook through its own InboxPopover branch, which draws errors.unknown on any error. So by source reading it shows 'An unexpected error occurred.' for the same 403. I did not reproduce this through a public door, so it is not filed. refused now reaches it, which makes it a one-branch follow-up. It is in PR Acceptance notes. Dedupe words: bell activity tab 403 unexpected error; InboxPopover sys_activity refused",
      "carrier: none (承接者:无) · noted, not filed: the 401 half — the shared verdict counts 401 as refused, so a 401 on this read also shows the permission sentence (the mapping's verdict from objectui#11195's triage, not a widening made here)"
     ],
     "deviations": [
      "Package-dir vitest run declared narrowed (see tests). The first narrowed invocation was refused by vitest-invocation-guard (overlapping path filter, exit 1 before any test ran) and is not a measurement. Its rerun is the one quoted.",
      "Clause-② stays no: no published export changed (ActivityFeedReading and useSharedActivityFeed are not in the app-shell barrel)."
     ],
     "files_changed": [
      "packages/app-shell/src/hooks/sharedUserFeeds.ts",
      "packages/app-shell/src/console/home/HomeRail.tsx",
      "packages/app-shell/src/console/home/__tests__/HomeActivity.refusedRead-12843.test.tsx",
      ".changeset/12843-home-activity-403.md"
     ],
     "gates": "see tests; all listed gates exit 0; check:spec-floors not run (not in the dispatch list)"
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT — objectui PR #12858 · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T04:50Z

    Reviewed on GitHub at head 1fc81da, against the card's Done-when, the triage note (6228766353) and the claim (6228800012, which carries the seat ruling: the same copy, not a hidden card).

    • Shape: the body says Fixes #12843; the second line is Clause-②: no. The changeset is @object-ui/app-shell: patch. ActivityFeedReading and useSharedActivityFeed are not in the app-shell barrel, so no published export changes.
    • The change:
      • A1, measured: the shared feed (sharedUserFeeds.ts) swallowed every non-404 rejection into markFailed(), so Home only ever saw status: 'error'.
      • The feed now classifies the rejection with isRefusedFeedRead, the record activity panel's verdict from objectui#11195, already a root export of @object-ui/plugin-detail. There is one classifier, and nothing was extracted. A new runner callback, markRefused(), publishes the same error state and backoff with refused: true on the snapshot. Every other snapshot keeps its two-key shape.
      • HomeActivity (console/home/HomeRail.tsx) shows the record panel's lock and detail.activityAccessDenied for a refused error. Every other failure keeps errors.unknown. The card is not hidden, no permission probe is added, and no new i18n key is introduced.
      • @object-ui/plugin-detail is already a declared dependency of app-shell, and isRefusedFeedRead already a runtime import there (RecordDetailView.tsx). Bundle Analysis: the performance budget passes, with an eager closure of 3135.8 KB against a 3744.1 KB budget.
    • Pins: HomeActivity.refusedRead-12843 (real useHumanActivityFeed into real HomeActivity, en catalogue): (a) a 403 PERMISSION_DENIED → the card's notice equals the text the record panel renders for the same refusal; (b) CONTROL: a 500 keeps "An unexpected error occurred."; (c) CONTROL: success renders the row. Ablation: an always-false guard in place of the isRefusedFeedRead branch turns only (a) red; the restore was proven by blob hash. 78 test files reading the feed, the bell or Home (921 tests) are green; app-shell type-check exits 0.
    • The dev's open question, answered by this seat: option A for this PR, the shared key as the ruling required. The visible cost is that Home's sentence ends "…on this record". The neutral sentence, and the header bell's Activity tab (which reads the same hook but still draws the generic error for the same 403), are one family: filed objectui#12859, to land after this card.
    • Acceptance notes, not filed: the shared verdict counts a 401 as refused too, so a 401 on this read also shows the permission sentence. That is objectui#11195's verdict, not a widening made here.
    • Trailers: both commits carry only the model-free pair.
    • CI at head: 33 success, 3 skipped, 0 failures (filter=latest, 36 runs). Not governed (path audit); 253 changed lines.

    Next: pr_ready + automerge_enable.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 17, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:ui seat 2 · session_01XVp19E1MYUTFM3dnkwz8gB · 2026-10-17T05:04Z

    PR #12858 merged through the merge queue as 024d446, which is on main; Fixes #12843 closed this card. Verified by content: all 4 of the PR's files on main are blob-identical to the accepted head 1fc81da. The merge commit's message names no model.

    What landed:

    • The shared activity feed marks a refused sys_activity read with objectui#11195's one verdict (isRefusedFeedRead).
    • Home's "Activity feed" card now shows the record activity panel's lock and permission sentence for it, instead of "An unexpected error occurred."
    • Every other failure keeps the generic copy. The card is not hidden.
    • Released as @object-ui/app-shell: patch.

    Follow-up filed: objectui#12859 (a neutral sentence for Home, which today ends "…on this record", and the header bell's Activity tab, which still shows the generic error for the same 403).

    This seat now removes pm:dispatched.


    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

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions