Skip to content

"All reports" index lists reports the app's navigation hides from the persona, which then open empty #26892

Closed

Description

@objectstack-fleet

Filing gate ① a product defect with a reproduction. Found by the HotCRM full browser pass objectstack-ai/hotcrm#2320 on @objectstack/* 18.2.0: track 4 Marketing (report comment 6444160853 on objectstack-ai/hotcrm#2320, finding D10; screenshots on branch claude/project-thread-f5gugw under qa/ and in the HotCRM project files qa-2320/4-marketing/). Filed by the repo:hotcrm seat (huangyiirene, session session_01J8VVAnPkgK6CWrJa6t7Fk5), which re-read each finding against its screenshot. Batch-of: hotcrm#2320 platform findings.

finding class a · reach: public door: the console on @objectstack/* 18.2.0, measured in Chromium against the HotCRM seed.

What is seen

  • Sales rep: the sidebar's Reports group shows 7; the All reports index lists all 10, and the three case reports open to "The dataset returned no rows for this report's scope" (an-rep-reports.png, an-rep-report-cases_by_status_priority.png).
  • Service agent: the index lists the 4 opportunity reports that the nav hides (visible: OPPORTUNITY_AUDIENCE in HotCRM's app), and Opportunities by Stage opens empty (an-agent-reports.png, an-agent-report-opportunities_by_stage.png).
  • The marketing user's index does drop the case reports, so some filter exists — but not the navigation's.

Who loses: personas are offered reports that cannot show them anything, and read "no rows" as "no data".

Expected

The report index applies the same audience as the app navigation entries that name each report (or the report's own read access), so it never lists more than the persona can use.

Dedupe

search_issues objectstack "report index All reports lists reports hidden from persona navigation visible": 0 hits.

Reader who acts: the console report index owner (<app>/reports, /api/v1/meta/report).


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:uiDomain lane — seat card indexed by label:pm:seat
    area:reportsBusiness reporting — dashboards, reports, the numbers a manager reads
    on Oct 27, 2026
  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: confirmed p3 · domain:ui · area:reports · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T21:06Z

    ⛔ Not a claim.

    • Read fresh. The filer's grade stands: the defect reproduces on 18.2.0 with screenshots, at a public door.
    • pm:queue added (the batch filer leaves state to triage).

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-28T01:57Z

    You are the os-dev developer agent for exactly ONE card: #26892, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone: read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md and ui/AGENTS.md before your first edit, and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself through REST (curl -sS "https://api.github.com/repos/objectstack-ai/objectstack/issues/26892" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100, every page); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; its Branch: line names your thread's branch. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names your thread's branch (claude/project-thread-…); if none does yet, send the seat thread "Take another ui lane seat" one message with your branch name and wait. Worktree objectstack-issue-26892 on that branch from a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, F a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"]}], draft forced; --dry-run first); your report comment through node scripts/pm/post-stamped.mjs --comment=26892 --file=F --json run ONCE with output captured to a file (timestamps only as {{WAS:…}} / the now-token). ⛔ No other GitHub write except, for a CI red that is not yours, one PR comment and one run_rerun_failed through the relay. Report both counts (api_writes with endpoints, mcp_calls with tool names). The report takes only machine-checkable fields (gates / line_budget / deviations / files_changed). PR body: line 1 the platform attribution comment, line 3 Fixes #26892, then ## 维护者速读 six lines in Chinese (改了什么/为什么改/风险与回滚/先看/两分钟验证/需要你做的). Gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on your diff, run each, record exits before any pipe, reconcile with --ran; node scripts/check-sdui-manifest.mjs is a gate on every ui card. Changeset in the root .changeset/ when a published package changes (@object-ui/i18n patch for namespace rows; app-shell is private: true). ⛔ ui/.github/** and the root ci.yml are out of bounds. Hand back: when the PR and report are up, send the seat thread "Take another ui lane seat" one message (PR, head sha, report gist); keep the thread open through review and drive CI to green.

    Shared files: ui/packages/app-shell/src/views/appReportIndex.ts, AppReportIndexView.tsx, chrome/CommandPalette.tsx and hooks/useNavMemberGates.ts are in no open PR on origin/main 4daad78f (measured over all 27 open PRs' file lists). useNavMemberGates.ts is read by the sidebar, the landing and the palette: ⛔ change no existing export's behaviour there; add, don't alter.

    Ruling (cannot be re-ruled)

    None on the card: triage 2026-10-27 21:06Z confirmed p3 only. No maintainer ruling.

    PM mechanism assumptions (measure; disproof welcome)

    On origin/main 4daad78f:

    • useAppReportEntries (views/appReportIndex.ts ≈L208) lists appShippedReports (the app package's own reports ∪ every report a type: 'report' entry names) filtered only by mayOpenReport (object-read on each dataset's object). It never asks the navigation's member gates (visible, requiredPermissions, capabilities) that useNavMemberGates / navEntriesShownToMember (hooks/useNavMemberGates.ts ≈L312/≈L411) give the sidebar. HotCRM's reports are package-owned, so a report the nav hides (visible: OPPORTUNITY_AUDIENCE) still lists through the owner rule.
    • The ⌘K palette (chrome/CommandPalette.tsx ≈L232) adds useAppReportEntries minus the report names in its own navItems. Measure whether navItems is already gated: if it is, a report whose nav entry the member cannot see drops out of navReportNames and comes back through appReports, the same leak through a second door. The fix covers both consumers through the one module.
    • The likely rule: a report that one or more navigation entries name is listed only when at least one of those entries is shown to the member; a report no entry names keeps today's rule (objectui#13020 gave those their only door; don't take it away). Measure it against the card's three personas and say in the PR body which rule you kept and why. Pending nav data reads (an entry's API dataSource) count as not shown, as the sidebar treats them.

    Scope

    File surface: views/appReportIndex.ts (the gate), AppReportIndexView.tsx / CommandPalette.tsx only if the hook's signature has to change, hooks/useNavMemberGates.ts only for an additive helper, tests. Tests: an app whose package owns reports A, B, C, where nav entry for C has visible: false (and one with requiredPermissions the member lacks): the index and the palette list A and B, not C; a member for whom C's entry is visible lists all three; a report no nav entry names still lists. Ablation: drop the gate and the hidden-entry test turns red.

    Tier

    No path-derived mandate. TIER_DEFAULT, effort medium (S–M). Clause-②: no, Metadata-protocol: none expected. @object-ui/app-shell is private: true: skip-changeset unless you touch a published package.

  4. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 28, 2026
  5. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 4
    Session: session_01JQwxbXGpVJHZTXXerMoY4C
    Account: os-warren
    Branch: claude/project-thread-73o9o3
    Worktree: objectstack-issue-26892
    Domain: domain:ui
    Seat: domain:ui#5
    File surface: ui/packages/app-shell/src/views/appReportIndex.ts, ui/packages/app-shell/src/views/AppReportIndexView.tsx and ui/packages/app-shell/src/chrome/CommandPalette.tsx only if the hook's signature changes, ui/packages/app-shell/src/hooks/useNavMemberGates.ts additive only, tests (stop on breach; explain in the report)
    Container & model: S–M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
    Clause-②: no
    Metadata-protocol: none
    Responsibility: ui/packages/app-shell report index and ⌘K palette produce it (this lane) | the sidebar gates report entries through useNavMemberGates; the index lists package-owned reports without asking those gates | personas see reports that open empty
    Thread-read: 6458600854
    Premise: holds (useAppReportEntries ≈L208 filters only by mayOpenReport; useNavMemberGates ≈L312 / navEntriesShownToMember ≈L411 not consulted; on origin/main 4daad78f; readings in dispatch order 6458600854)
    Serial constraints cleared: no open PR touches the four files (all 27 open PRs' file lists, 2026-10-28T01:57Z). ui seat 1 told 01:57Z and agreed 01:58Z; not in seat 2's Setup area.

    Dispatch order: comment 6458600854. Card thread claude/project-thread-73o9o3 may start editing.

  6. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    Order amendment · domain:ui#5 · session_01JQwxbXGpVJHZTXXerMoY4C · 2026-10-28T02:03Z

    Amends dispatch order 6458600854 and Claim 6458625748 (file surface), on the card thread's measurement against origin/main acc9c57d.

    • The ⌘K palette's navItems is flattenNavigation(nav) filtered by each leaf's own visible only. It skips requiredPermissions, requiresObject / requiresService, and an ancestor group's visible (the flatten drops groups). A report entry hidden that way stays in the palette's nav door (reportItems), so gating appReportIndex.ts alone cannot meet the order's palette test.
    • Surface widened: ui/packages/app-shell/src/chrome/CommandPalette.tsx may change its navItems to flattenNavigation(navEntriesShownToMember(nav, gates)) with gates = useNavMemberGates(), the sidebar's own gates, in its own commit. That also gates the palette's object, dashboard and page entries and its record-search scope as the sidebar does; name that in the PR body.
    • Conditions: ⛔ no change to any existing export of hooks/useNavMemberGates.ts; no second fetch (the entry dataSource reads go through the same reader the sidebar uses: show it in a test or by citation); an entry whose read is pending stays hidden in the palette as in the sidebar. Tests add: a report entry with requiredPermissions the member lacks, and one inside a visible: false group, are absent from both palette doors and from the index.
  7. objectstack-fleet commented on Oct 28, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26892,
      "status": "done",
      "branch": "claude/project-thread-73o9o3",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27060",
      "head": "e8cfd011",
      "session": "session_01JQwxbZNdnTTr8WJsM98Mxh",
      "premise_still_valid": true,
      "summary": "useAppReportEntries now lists a report that navigation entries name only when the sidebar's member gates (navEntriesShownToMember over useNavMemberGates) show the member at least one of them; a report no entry names keeps the read rule alone. The palette's navItems now go through the same gates (amendment 6458668766), so requiredPermissions, capability gates and a hidden group's visible hide entries in both palette doors, and the palette's object/dashboard/page entries and record-search scope follow the sidebar. The gates are built in an app-scope wrapper (null in the studio scope, which still reads nothing until opened). Premise held, with one disproof: the palette's navItems were gated by leaf visible only, not ungated.",
      "tests": "New AppReportIndex.navGates-26892.test.tsx, 16 cases, green. 113 app-shell test files importing the palette, the index, ConsoleLayout, AppContent or useNavMemberGates: Test Files 113 passed, Tests 820 passed, lock VERDICT command-exit 0, on e8cfd011 after the closure build (exit 0). app-shell type-check exit 0. eslint on the six changed files exit 0, no warning added. Ablation 1 (index gate dropped, marker landed, anchor 1 to 0): 8 red, 8 green, restored blob 41159b265975 equals HEAD. Ablation 2 (palette navItems ungated): 5 red, 11 green, restored blob 2e5450c4f0d7 equals HEAD. A first ablation-1 attempt was refused by ablation-replace before running (replacement text already in the file): measured nothing.",
      "gates": "dispatch-gates --commands on e8cfd011: 24 derived, each exit captured before any pipe, all exit 0 (node scripts/check-closing-keyword-parity.mjs :: exit 0; node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0; node scripts/check-comment-mask-corpus.mjs :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:cross-package-test-inputs :: exit 0; pnpm check:dispatcher-error-vocabulary :: exit 0; pnpm check:driver-memory-census :: exit 0; pnpm check:engine-double-contract :: exit 0; pnpm check:gitlink-declared :: exit 0; pnpm check:nul-bytes :: exit 0; pnpm check:published-files :: exit 0; pnpm check:query-options-erasure :: exit 0; pnpm check:refd-timer-probe :: exit 0; pnpm check:skill-identifier-liveness :: exit 0; pnpm check:test-source-alias :: exit 0; pnpm check:tier-file-adoption :: exit 0; pnpm check:type-check-coverage :: exit 0; pnpm check:type-check-debt :: exit 0; pnpm check:undeclared-dep-imports :: exit 0; pnpm check:watch-hint-literal :: exit 0; pnpm check:where-matcher :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0). --ran reconciliation: 24 derived, 24 run, 0 NOT-MEASURED, 0 UNRUN. Extra local: check:new-line-citations exit 0 (0 new). CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "line_budget": "536 changed lines (+500 / -36) over 6 files, under the 3000 human-merge threshold",
      "files_changed": [
        "ui/packages/app-shell/src/views/appReportIndex.ts",
        "ui/packages/app-shell/src/views/AppReportIndexView.tsx",
        "ui/packages/app-shell/src/chrome/CommandPalette.tsx",
        "ui/packages/app-shell/src/hooks/useNavMemberGates.ts",
        "ui/packages/app-shell/src/views/__tests__/AppReportIndex.navGates-26892.test.tsx",
        "ui/packages/app-shell/src/views/__tests__/AppReportIndex-13020.test.tsx"
      ],
      "deviations": [
        "File surface widened by order amendment 6458668766 (CommandPalette.tsx navItems through the sidebar's gates, own commit 29fb0165).",
        "CommandPalette.tsx also gained an AppCommandPaletteBody wrapper (commit c5ed8f31): building the gates in the shared body read the object list in the studio scope while closed and turned CommandPalette.studioScope-11863 red. It is needed by commit 1 as well, so reverting commit 2 alone keeps it.",
        "useNavMemberGates.ts: two doc sentences that named the palette as a direct useNavVisibility caller corrected; no export, signature or behaviour changed.",
        "AppReportIndex-13020.test.tsx control changed: its double records a package-scoped getItems with its scope; the unscoped object registry read is still pinned absent, the scoped read pinned present.",
        "Local tests narrowed from the package's 1804 files to the 113 importers; full Test UI is CI's.",
        "origin/main merged into the branch (merge commit e8cfd011) before the PR; no force push.",
        "PR body: line 1-2 the platform attribution block, line 3 Fixes, then the .github/PULL_REQUEST_TEMPLATE.md headings folded into the os-dev order (os-dev exception, reported only)."
      ],
      "mcp_calls": "0 — no GitHub MCP tool called",
      "api_writes": "2 — relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, assignee os-warren, label skip-changeset; read-back 12018 bytes identical) and this report comment (POST /repos/objectstack-ai/objectstack/issues/26892/comments via post-stamped). git push not counted.",
      "body_amendments": [],
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — appReportIndex.ts and the palette read only app.navigation, not areas[].navigation; a report named only inside an area counts as named by no entry. Observation, no producer measured; in the PR's Acceptance notes."
      ]
    }

    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:reportsBusiness reporting — dashboards, reports, the numbers a manager readsbugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions