Skip to content

Dashboard: a viewer whose analytics queries are all refused 403 sees a blank canvas under the title (CRM Pipeline Dashboard as a plain member), with no per-widget refusal #27491

Closed

Description

@objectstack-fleet

domain:devx#1 · sunhaolin · session_017xRBcUoS2G4jgqRskpExS7

Found in the 18.3.0 release-candidate browser walkthrough (wave anchor #27377, card W3-UX), at framework main @ c4c515ad, Console built in-repo from the same commit.

Repro (fresh boot)

  1. Boot examples/app-crm with --seed-admin. As admin, invite member1@example.com with role member. Sign that address up and sign in as the member through the form. Viewport 1440×900.
  2. The CRM landing says "Nothing in CRM is available to you yet". The sidebar still offers Analytics → Pipeline. Click it.

Expected

Each widget draws its refusal ("You don't have access to this data"), which is the behaviour #26971 describes for a tile whose dataset the viewer cannot read. Or the dashboard is not offered.

Actual

The title, the description and Refresh All render over an empty canvas. There is no widget frame, no message and no error. The network shows POST /api/v1/analytics/dataset/query answering 403, and the page swallows it. The same member gets a proper refusal state on the Opportunities list.

QA-source: #27377 · ux-walkthrough · track 1


Generated by Claude Code

Activity

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

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 经营报表 | none | P②

    Triage: p2 · domain:ui · area:reports · 2026-10-29T11:56Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Blocked-by: #27560 · 2026-10-29T19:32Z


    Generated by Claude Code

  4. added
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 29, 2026
  5. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Unblocked · 2026-10-29T20:55Z: the blocker landed. PR #27560 (#27460) merged at 2026-10-29T20:03Z. Labels move from pm:blocked to pm:queue. Seat 2 dispatches this card next, and its Claim: follows.


    Generated by Claude Code

  6. added
    pm:queueReady for the PM dispatch loop
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:blockedBlocked by another issue/PR — body carries Blocked-by: #N
    pm:queueReady for the PM dispatch loop
    on Oct 29, 2026
  7. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Claim: PM loop round 1 · 2026-10-29T20:57Z
    Session: session_01Utp6CY2n1JmZZKrHgtp9jC (seat; implementation by a card thread, mode:thread)
    Account: os-bill
    Branch: claude/project-thread-x22lgi (the card thread's harness push branch, self-reported — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-27491
    Domain: domain:ui
    Seat: domain:ui#2
    File surface: ui/packages/plugin-dashboard/src/DashboardRenderer.tsx, DatasetWidget.tsx, their tests, i18n keys if needed, a changeset; ⛔ packages/spec/**, every server file, examples/**, the console nav
    Container & model: M, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: no (expected; the dev measures from the diff)
    Metadata-protocol: none (expected; the dev measures from the diff)
    Responsibility: the dashboard renderer's face for a viewer whose every dataset tile is refused 403 | the server's 403 is the enforcement and a fixed input | every member who opens a dashboard none of whose datasets they can read, today
    Thread-read: 6508127342
    Premise: questioned by the seat: #26971 made a refused tile drop out for a viewer (DashboardRenderer.tsx refusedTiles), so the all-refused blank may be that rule, not a swallowed 403; step 1 of the order measures it and returns needs_decision if the triage ruling and #26971 collide
    Serial constraints cleared: #27560 (#27460, same DatasetWidget.tsx) merged 2026-10-29T20:03Z; sibling card #27563 (seat 2) may touch DatasetWidget.tsx, so whichever PR lands second rebases

    Dispatch order: /mnt/project-files/ui-seat2/dispatch-27491.md in the Claude Code project (not on GitHub); its ruling section quotes the triage text above verbatim.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    os-dev-report

    {
      "issue": 27491,
      "status": "needs_decision",
      "branch": "claude/project-thread-x22lgi",
      "pr": null,
      "session": "session_01Utp6CXTsLkvW2GpvDwNQre (card thread; seat session_01Utp6CY2n1JmZZKrHgtp9jC)",
      "premise_still_valid": false,
      "summary": "The blank canvas is the #26971 rule working as built, not a swallowed 403. On origin/main 525ea363 the CRM pipeline_dashboard has six widgets, all bound to dataset opportunity_metrics. For a member, POST /api/v1/analytics/dataset/query answers 403 PERMISSION_DENIED; the adapter throws AnalyticsForbiddenError (httpStatus 403, code PERMISSION_DENIED, data-objectstack index.ts ~L6965-6976); DatasetWidget classifies it forbidden and calls onForbidden (DatasetWidget.tsx ~L972-974); DashboardRenderer then returns null for that tile outside design mode (DashboardRenderer.tsx L1105). With all six refused nothing is left under the header. The spec now documents that hide: packages/spec/src/ui/dashboard.zod.ts L1095-1100 ('is left out of the dashboard for that viewer'), landed through #27068, and #26971's own report listed the all-refused blank as noted, not filed. The triage ruling 'Render each widget's refusal with the existing #26971 tile refusal state. No new dashboard-level error path.' cannot be met as written: the #26971 state for a viewer is the tile left out, and drawing each refusal contradicts the spec docblock. No code written; product choice below.",
      "tests": "Scratch measurement only (file deleted, never committed): plugin-dashboard test rendering the real examples/app-crm pipeline_dashboard through the real ObjectStackAdapter, fetch stubbed to answer every dataset query 403 with code PERMISSION_DENIED. Viewer render: 6 queries for 6 widgets, 0 forbidden faces, 0 widget titles left, container text empty. CONTROL design mode: 6 forbidden faces. Ablation via scripts/ablation-replace.mjs --delete on DashboardRenderer.tsx L1105 (anchor 1 -> 0, blob 873014377988 -> 3fd7eb20f874): the viewer case goes red (the six titled frames stay), design control green; restored, blob == HEAD 873014377988, git diff HEAD empty. So the blank has no other source. Closure build --filter '@object-ui/plugin-dashboard^...' VERDICT command-exit 0; measurement run VERDICT command-exit 0.",
      "gates": "none run: no diff (needs_decision). check-sdui-manifest not applicable without a change.",
      "dogfood_battery": "n/a - no PR",
      "line_budget": "0 changed lines",
      "files_changed": [],
      "deviations": [
        "Measured with a unit equivalent (real dashboard definition + real adapter, stubbed fetch), not a live browser run on app-crm."
      ],
      "mcp_calls": "5 GitHub MCP reads (issue_read get x2, get_comments x2, search_issues x1); no GitHub MCP write tool.",
      "api_writes": "1 - this os-dev-report comment via post-stamped (POST issues/27491/comments). No push, no PR.",
      "open_questions": [
        {
          "question": "A member opens a dashboard none of whose data they may read. What should they see?",
          "governing_text": "triage 6495993447 ('Render each widget's refusal with the existing #26971 tile refusal state. No new dashboard-level error path.'); spec dashboard.zod.ts L1095-1100 and the requiresObject describe L1162 (a refused dataset tile 'is left out of the dashboard for that viewer'); #26971 dispatch 6459370946 (seat chose 'leave the tile out').",
          "options": {
            "A": "Keep the per-tile hide. When every tile has been left out for the viewer, DashboardRenderer draws one 'You don't have access' panel in the canvas, the same face DashboardView already shows for a refused dashboard (dashboard-access-denied). ui lane, 1 PR in plugin-dashboard plus one new message key in ten locales; precedent #27065 (+185/-1). Agrees with the spec; overrides the triage's 'no new dashboard-level path' wording.",
            "B": "When every tile is refused, draw each tile's own refusal face (the #10899 state design mode shows); a partial refusal keeps the hide. Literal match to the triage and the card's Expected. Contradicts the spec docblock, so it needs a spec-lane docblock change too (precedent #27068), and makes a tile's face depend on its siblings: the last refused tile flips all of them back on.",
            "C": "Do not offer the dashboard: the app declares the dashboard-level audience gate (requiredPermissions, #22611/#22639) on pipeline_dashboard and the nav item, so a member never reaches it. App lane (examples/app-crm), outside this card. Fixes CRM only; any other dashboard whose tiles are all refused still shows the blank."
          },
          "four_axis": {
            "long_term": "A keeps one rule (a refused tile leaves) and adds the one canvas state a page with nothing left needs, in the words the console already uses for a refused dashboard; mainstream BI does the same (a report whose data you cannot read says so once). B adds a sibling-dependent special case and reopens a documented spec sentence. C is the right complement for app authors but does not cover the renderer case.",
            "business_need": "Today every plain member who clicks Analytics > Pipeline in CRM sees a blank page (card repro). A and B both give them a statement; C removes the entry for CRM only.",
            "ai_error_prevention": "A: an all-refused dashboard says so loudly, no metadata involved. B: a reader sees N identical refusals, still loud. C relies on each app author declaring the gate; a forgotten gate falls back to the silent blank.",
            "startup_scope": "A: 1 PR, one new i18n key, no spec. B: 2 PRs across two lanes. C: 1 small app PR, no platform change."
          },
          "recommendation": "A. Only axis 1 picks A; axes 2-4 do not flip it. C can follow separately as app hygiene. Confidence gap: not run live on app-crm in a browser."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CavdFhhfMVhuGjp7tP

    Ruling: what a viewer sees on a dashboard whose every dataset tile the server refuses (project discussion thread 「决定仪表盘全部无权限时的显示」) · letter A · maintainer 「A」 2026-10-29T21:41Z

    The maintainer's own ruling, given in the project thread at 2026-10-29T21:39Z on the review thread's six-section analysis (/mnt/project-files/decisions/27491-仪表盘全部无权限-呈批.md, recommendation A, which the card thread's report 6508422494 and domain:ui#2's brief also recommended). Marker: maintainer-ruled, presented by the review thread; not a proxy ruling. It settles the collision between triage 6495993447 and the #26971 hide rule the spec documents.

    What was re-verified (code read at d93d9be5 on main)

    Governing text

    The ruling: A

    The per-tile hide stays as the spec states it. When, outside design mode, the renderer has at least one refused tile and no widget left to draw, it draws one canvas-level no-access panel in the same face DashboardView already uses for a refused dashboard. A partial refusal keeps today's behaviour (the refused tiles leave, the rest reflow, no message).

    Fixed here:

    1. Trigger: !designMode && refusedTiles.size > 0 && <zero widgets rendered>. Not "every dataset tile refused": a dashboard that still has a non-dataset widget (text, iframe, object-bound inline) draws those and no panel; a dashboard with zero widgets to begin with draws no panel (refusedTiles is empty).
    2. Face: the Empty composition of DashboardView's dashboard-access-denied (lock icon; title dashboard.widgetForbiddenTitle; one NEW message key dashboard.allWidgetsForbiddenMessage, en "You don't have permission to view the data behind this dashboard.", in all ten locales under ui/packages/i18n/src/locales/); data-testid="dashboard-all-widgets-forbidden". Header title, description and "Refresh All" stay as they are (a refused tile is not re-queried until remount, fix(plugin-dashboard): leave a tile out when the server refuses its data to the viewer #27065; unchanged).
    3. Pins (one new test file beside DashboardRenderer.refusedTile-26971.test.tsx): all refused → panel, no tile title, no per-tile face; partial refusal → no panel, readable tile present; CONTROL design mode, all refused → no panel, every tile's objectui#10899 face present; CONTROL non-refusal failure (400) on every tile → no panel, error alerts present.
    4. Surface: ui/packages/plugin-dashboard/src/DashboardRenderer.tsx, the new test, ten locale files, changesets @object-ui/plugin-dashboard patch and @object-ui/i18n patch. ⛔ No spec change, no DatasetWidget change, no DashboardView change, no examples/**.
    5. C runs beside A, not instead: domain:ui#2 files one S card in the app lane: examples/app-crm declares requiredPermissions on pipeline_dashboard and on nav_pipeline_dashboard, with a capability one of the CRM sales permission sets actually grants; acceptance = a member's sidebar has no Pipeline entry and a direct link gets dashboard-access-denied. Not paired with this PR.
    6. ⛔ Not: per-tile faces when all are refused (B: contradicts the spec sentence and makes a tile's face depend on its siblings); any client-side permission guess that hides a nav entry or a dashboard before the server answers (D); any change to the partial-refusal behaviour or its 26971 pins.

    Why A, on the four axes (business standpoint)

    Only-① pick: A. Do ②③④ flip it: no. Effort for the chosen letter: S.

    ① 长远:「读不到就拿掉」已经 #26971 → #27065 → #27252 三道进了 spec,A 不动它,只补它没覆盖的空集(一个都没剩时说一句);B 为边角重开刚合入的 spec 句子,且卡片的面取决于兄弟;C 是应用作者的事,盖不住渲染器。
    ② 拉动:18.3.0 RC 走查实测(#27377 W3-UX);每个没拿到权限集的成员,在任何「数据集全在同一对象」的仪表盘上都会撞到,CRM Pipeline 六块一个数据集就是。
    ③ 防错:A 响亮且只在渲染器确实一个都没画时出现,不读元数据、不猜权限;B 状态机多一维;C 靠作者记得声明门,忘了就回到空白。
    ④ 不扩散:A 一包一分支一键,S;B 两车道;C 应用车道另立卡。
    Prior rulings read: #26971 triage 6456651336、PR #27065 Acceptance notes、#27068 / PR #27252、objectui#12112(dashboard-access-denied 面)、objectui#10899(卡片自己的无权限面)、#22611 / #22639 / ADR-0066(仪表盘 requiredPermissions,服务器强制);本卡:triage 6495993447、Claim 6508167825、报告 6508422494。

    Execution after the ruling

    • The card stays pm:dispatched on domain:ui#2; the card thread resumes on claude/project-thread-x22lgi with Ruling-ref: <this comment id>, builds items 1–4 above, then gates, draft PR (Fixes Dashboard: a viewer whose analytics queries are all refused 403 sees a blank canvas under the title (CRM Pipeline Dashboard as a plain member), with no per-widget refusal #27491) and os-dev-report per the seat's flow; non-governed surface, lands after ACCEPT + PASS per the seat's flow.
    • domain:ui#2 files the C card (item 5) through the relay; its wording is that card's.
    • Spec-lane hygiene, not this card: the JSDoc above DashboardSchema.requiredPermissions (dashboard.zod.ts ≈L1779, "including why it says the gate is not enforced yet") is stale — the describe already says the server enforces it. One sentence, to ride along with the next spec card.
    • Not reopened: the per-tile hide; the 26971 pins; DatasetWidget's own face; "Refresh All" behaviour on refused tiles.

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Ruling 6508997538 item 5 is done: the C card is filed as #27735 (app lane, examples/app-crm Pipeline audience gate), not paired with this card. It goes to triage unlabelled. Measured while filing: the CRM permission sets grant no capability today, so the gate needs one added to the sales set(s). The card says so.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    os-dev-report

    {
      "issue": 27491,
      "status": "done",
      "branch": "claude/project-thread-x22lgi",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27777",
      "head": "24bc0b979f6d04c7f2e683aecf7902e3b73e47d5",
      "session": "session_01Utp6CXTsLkvW2GpvDwNQre (card thread; seat session_01Utp6CY2n1JmZZKrHgtp9jC)",
      "premise_still_valid": true,
      "summary": "Ruling A (Ruling-ref 6508997538), items 1-4. DashboardRenderer renders its tiles once per layout (desktopTiles; metricTiles/otherTiles on mobile) and, outside design mode, when at least one tile is refused and every rendered tile is null, draws one Empty panel (lock icon, dashboard.widgetForbiddenTitle, new dashboard.allWidgetsForbiddenMessage, data-testid dashboard-all-widgets-forbidden, col-span-full) after the tiles; header, description and Refresh All untouched. The refusal drop is the only null a tile renders, so the trigger is exactly nothing left. New key in all ten locales. No spec, DatasetWidget, DashboardView or examples change. The first report of this card (6508422494) carried the premise reading that led to the ruling.",
      "tests": "New ui/packages/plugin-dashboard/src/__tests__/DashboardRenderer.allTilesRefused-27491.test.tsx, 5/5: all refused (panel, both tiles queried, no tile title, no per-tile face); same on mobile (2-column grid drawn); partial refusal (no panel, readable tile present); CONTROL design mode (no panel, 2 per-tile 10899 faces); CONTROL 400 on every tile (no panel, 2 error alerts). With the 26971 and 10899 files: 3 files, 11 tests passed. Ablation via scripts/ablation-replace.mjs on 76be3079: trigger condition replaced by false (anchor 1 -> 0, blob c9adcbb0354a -> eb6c069cbd78): 2 failed / 3 passed (the two all-refused cases red); restored, blob == HEAD c9adcbb0354a, git diff HEAD empty; relative import, no dist leg. At 24bc0b97 (after merging main): closure build --filter '@object-ui/plugin-dashboard^...' VERDICT command-exit 0; pnpm --dir ui exec vitest run --maxWorkers=2 packages/plugin-dashboard/ packages/i18n/ under the lock: Test Files 286 passed (286), Tests 3266 passed, 19 skipped, VERDICT command-exit 0.",
      "gates": "At 24bc0b97: dispatch-gates --commands --repo objectstack-ai/objectstack derived 34; all run, --ran: 34 derived, 34 run, 0 NOT-MEASURED. node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0; node scripts/check-adr-0087-registration.mjs --self-test :: exit 0; node scripts/check-changeset-no-major.mjs --base origin/main :: 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-empty-changeset.mjs --base origin/main :: exit 0; node scripts/check-empty-changeset.mjs --self-test :: exit 0; node scripts/check-sdui-manifest.mjs :: exit 0; node scripts/check-sdui-manifest.mjs --self-test :: exit 0; node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0; node scripts/release-pending-publish.mjs --self-test :: exit 0; pnpm --dir ui exec vitest run scripts/ :: exit 0; pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0; pnpm check:changeset-gate-self-tests :: exit 0; pnpm check:closed-ceremony-text :: 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:pm-changeset-deadline-census :: 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. Outside the derivation: pnpm --filter @object-ui/plugin-dashboard run type-check :: exit 0; pnpm --filter @object-ui/i18n run type-check :: exit 0; eslint on DashboardRenderer.tsx and the new test :: exit 0; pnpm --dir ui run check:new-line-citations :: exit 0. CI check-runs: in progress at report time.",
      "dogfood_battery": "n/a - no ! in the PR title and no narrowing arm",
      "line_budget": "232 changed lines (+227 / -5) vs origin/main: DashboardRenderer.tsx +31/-5, new test +169, ten locale files +1 each, changeset +17; under the 3000 human-merge threshold",
      "files_changed": [
        ".changeset/27491-dashboard-all-tiles-refused-panel.md",
        "ui/packages/plugin-dashboard/src/DashboardRenderer.tsx",
        "ui/packages/plugin-dashboard/src/__tests__/DashboardRenderer.allTilesRefused-27491.test.tsx",
        "ui/packages/i18n/src/locales/{ar,de,en,es,fr,ja,ko,pt,ru,zh}.ts"
      ],
      "deviations": [
        "en string uses the typographic apostrophe (You don’t ...) like the neighbouring dashboard.* strings; the ruling quoted it with a straight one.",
        "Commit trailers use the model-free pair per AGENTS.md, not the harness-suggested model-named co-author.",
        "The harness's post-PR assignee/reviewer step was skipped, per the maintainer's routing rule (no assignee, no reviewer before seat ACCEPT + review).",
        "No docs page edited (ui/AGENTS.md #2): the dispatch's file surface excludes docs; the behaviour is the renderer's state, not a new authorable feature."
      ],
      "mcp_calls": "6 GitHub MCP reads over the card's life (issue_read get x2, get_comments x2, search_issues x1, plus get_session which is not GitHub); no GitHub MCP write tool.",
      "api_writes": "3 over the card's life - report 6508422494 (needs_decision) and this report via post-stamped (POST issues/27491/comments); relay pr_create (draft, no assignee, no reviewer) run 40969030266, body read back identical (6032 bytes). Plus git pushes of the branch (not REST).",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    ACCEPT → PR #27777 comment 6510701042 (head 24bc0b97), under ruling A (6508997538). Contract review not owed (Clause-②: no, Metadata-protocol: none). Landing through the merge queue. Ruling item 5 is filed as #27735.


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC

    Landed · 2026-10-29T23:43Z

    probe reading
    PR #27777 merged through the queue at 2026-10-29T23:43Z, merge commit e7dda2cc2cee08d36f61a77e82daf854f55b56af
    this card closed completed by the PR's Fixes line

    State: pm:dispatched removed; the assignee stays as the record of who carried it.


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 30, 2026

    @objectstack-fleet
    ContributorAuthor

    director#1 · os-bill · session_01Utp6CavdFhhfMVhuGjp7tP

    Amendment to ruling 6508997538 item 5 · 2026-10-30T01:37Z

    Item 5's mechanism (a declared capability required on pipeline_dashboard and its nav entry) is replaced by the maintainer's ruling on #27735 (comment 6512784198, letter G, 「同意」 at 2026-10-30T01:34Z): the CRM hides the Pipeline nav entry with visible: "current_user.can('crm_opportunity', 'read')", declares no capability and gates no dashboard. Measured reason: a stack-level capability declaration makes the CRM refuse an unmanaged install (UNMANAGED_INSTALL_UNCOPYABLE, the dogfood specimen; 11 failures), and the gate closed the dashboard to the seeded administrator, in Studio included. Item 5's intent (the member is not offered the Pipeline) stands. Items 1–4 and 6 of 6508997538 (the all-refused panel, PR #27777) are unchanged; a direct link for the refused member lands on that panel.


    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:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions