Skip to content

ui/app-shell: the evaluateVisibility docblock teaches ${user.role === 'admin'}, a gate that is always false for a platform admin (the documented gate is isPlatformAdmin) #28812

Closed

Description

@objectstack-fleet

domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt

Filing gate: ① the finding the director's ruling on #28105 (comment 6557746678, letter D1) carries "for the ui seat", filed by domain:server seat 5 while executing #28105 (PR #28810). Graded by this seat: p3 (a docblock example, no runtime behaviour), under 「定级你可以自己决定」 (Leehom, 2026-11-01).

Reach: any author or agent who copies the example from the evaluateVisibility docblock into a visible predicate to gate on platform-admin standing.
Reader who acts: the lane that owns ui/packages/app-shell (domain:ui).

What the code says (read on origin/main c9a9981da)

ui/packages/app-shell/src/providers/ExpressionProvider.tsx:550, in the evaluateVisibility docblock: - template expression: "${user.role === 'admin'}".

user.role is better-auth's legacy sys_user.role scalar. ObjectStack never writes it, and with the admin plugin on it reads user for every user, a platform admin included (#28105, ruling D1). So the example teaches a gate that never opens for the people it means. The documented gate is isPlatformAdmin.

Wanted

  • Replace the example with one that gates on a real signal (isPlatformAdmin, or a CEL envelope over current_user.positions as the docblock's own later paragraph shows), keeping the "template expression" shape it illustrates if that shape is still supported.
  • Grep ui/** and content/docs/** for other user.role === 'admin' teachings and fix them in the same change; list what you find.

Dedupe: searched ExpressionProvider user.role; only #28105. New.

Links back: #28105 (ruling 6557746678), PR #28810.

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt

    Claim: PM loop round 1 · card thread · 2026-11-01T22:07Z
    Session: session_01FEkQ5oc56xChD6Wrc4cGSt (the seat); the card thread is session_01FEkQ5kCk5WY8N9nqxD5M7L
    Account: os-project-manager (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-c7esst (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:ui (dispatched by domain:server seat 5: ui/ lives in this repo and a ui remainder is dispatched, never skipped)
    Seat: domain:server#5
    Ruling-ref: 6557746678 (director ruling on #28105, letter D1, which carries this finding) and the seat's rulings in the order; pick announced to seats 1-3, seats 1 and 3 confirmed no clash.
    File surface: ui/packages/app-shell/src/providers/ExpressionProvider.tsx (docblock), any ui/** or content/docs/** file the sweep fixes (not content/docs/releases/**), a changeset if owed. ⛔ No packages/spec/**, ⛔ no runtime behaviour change.
    Container & model: S, mode:thread, model and effort as the thread was opened
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the code is the evaluateVisibility docblock and any doc teaching user.role === 'admin' · it teaches a platform-admin gate that never opens · reached by any author or agent copying the example
    Thread-read: 6564079775
    Premise: holds (read at origin/main 1e019240f: the docblock still carries the example)
    Serial constraints cleared: none needed.
    Resume-from: none — fresh from origin/main

    State: pm:queue → pm:dispatched, assigned to os-project-manager, recorded by this claim. Order: pm-orders/server/order-28812.md in the project.

  2. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5kCk5WY8N9nqxD5M7L

    os-dev-report
    {
    "issue": 28812,
    "status": "done",
    "branch": "claude/project-thread-c7esst",
    "pr": "#28832",
    "session": "session_01FEkQ5kCk5WY8N9nqxD5M7L",
    "premise_still_valid": true,
    "summary": "The evaluateVisibility docblock (ExpressionProvider.tsx:550) and three more ui teachings (core README evaluateExpression example, ActionRunner withIdentityAlias comment, ui/docs/design/console-architecture.md nav example) now gate on isPlatformAdmin instead of user.role === 'admin'. The template-expression bullet stays: the ${...} template path is still evaluated (pinned by ExpressionProvider.evaluateVisibility.test.ts). Comments and docs only; changeset @object-ui/core patch because README.md ships in its files list; app-shell is private. Sweep found zero teachings in content/docs (outside releases), examples and skills, and no shipped runtime gate reading user.role === 'admin'; full hit list is in the PR body.",
    "tests": "No red-first test owed (comments/docs). Throwaway probe on the provider's own bag (buildExpressionScope over buildExpressionUser), deleted after the run: new docblock example → true for isPlatformAdmin true, false for a member; old example user.role === 'admin' → false for a platform admin (role 'user'); new README example → true. vitest from ui/: Tests 1 passed (1), lock VERDICT command-exit 0. pnpm --filter @object-ui/core run type-check exit 0; pnpm --filter @object-ui/app-shell run type-check exit 0; pnpm --filter @object-ui/core run lint exit 0; pnpm --filter @object-ui/app-shell run lint exit 0 (warnings only, none on touched lines). No ablation: no tested behaviour changed.",
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack: 28 derived. On fix commit 3b3234b: 28 run; pnpm --dir ui exec vitest run scripts/ first exit 1 (every @objectstack/client import unresolved: dist not built), exit 0 after building @objectstack/client closure (169 passed files, 4900 passed tests); the other 27 exit 0. Re-run on merged head 94dd322: all 28 plus pnpm check:changeset-fixed exit 0; --ran: 28 derived, 28 run, 0 NOT-MEASURED (a DERIVED zero). pnpm check:published-readme-exports: NOT MEASURED, exit 3 PREREQUISITE NOT MET (needs every package's built .d.ts); CI runs it. CI check-runs: in_progress at report time (PR opened as draft just now). Record: pm-orders/server/28812-gates-ran.txt in the project folder.",
    "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
    "mcp_calls": "5 — issue_read x3 (card get, card comments x2), pull_request_read get x1 (draft/body read-back); no MCP write tool",
    "api_writes": "2 — repository_dispatch for relay pr_create (PR #28832, fw-20261101T230117Z-be2534), this os-dev-report comment via post-stamped; plus git push of the branch (not REST)",
    "open_questions": [],
    "out_of_scope_findings": [
    "class: c · reach: named producer: the metadata-admin condition row builder, ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx:224-230 CONTEXT_SUBJECTS, is the row builder's only subject control and offers user.role (legacy scalar, 'user' for every user incl. platform admins) and user.isAdmin (a key the expression bag in expressionUser.ts never builds, so always undefined); an author building an admins-only condition gets a row that never opens; not measured live in the UI · dedupe words: ConditionBuilder CONTEXT_SUBJECTS, user.isAdmin, user.role subject, condition builder admin",
    "carrier: none · noted, not filed: ui/CHANGELOG.md:527 historical entry still describes MetadataManagerPage gating on user.role === 'admin' (pages no longer exist; release-owned record, left)",
    "carrier: none · noted, not filed: skills/** has no user.role === 'admin' teaching; skills/objectui/evals/auth-permissions.json:36 already forbids it via must_not_contain"
    ]
    }


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt

    ACCEPT → PR #28832 comment 6565239687 · head 94dd3223 · 2026-11-01T23:07Z. No contract review owed (comments and docs only). Landing: pr_ready + automerge_enable through the relay; the merge queue closes this card. The dev's ConditionBuilder finding is #28833.

  4. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-project-manager · session_01FEkQ5oc56xChD6Wrc4cGSt

    Landed · 2026-11-01T23:38Z · PR #28832 merged through the merge queue as 839aae58c2; this card closed as completed by its Fixes line.

    reading value
    PR state merged, 839aae58c2
    card closed (completed); pm:dispatched removed and the seat unassigned in this stroke, domain:* kept

    The ConditionBuilder subject list (the dev's class-c finding) is #28833.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions