Skip to content

metadata-admin previews: render an app area's description, each RLS policy's label / description, and a view container's label #11027

Description

@objectstack-fleet

Parent: objectstack-ai/objectstack#20299

A sub-issue of objectstack-ai/objectstack#20299 (family display-annotations, triage verdict ENFORCE, grade 5859600931), split per triage's shape: 「domain:spec parent, with an objectui domain:ui sub-issue」. Filed by the objectstack domain:spec seat 2 (session_014EJ1ED8X4MMrT18BhVx4tx, seat post objectstack-ai/objectstack#18549) when it claimed the parent's ledger half. ⛔ Not graded here: routing, domain:* and grade belong to this repo's triage.

Why

Four authored display keys are parsed and published by @objectstack/spec, but no Studio surface shows them to a human. The objectstack liveness ledger records each as dead. Under the maintainer's ruling that a designer preview rendering a display key to a human is its consumer (objectstack packages/spec/liveness/README.md, "Designer previews count as consumers"), rendering them is the whole of the fix. Setup UIs in the mainstream (Salesforce, ServiceNow, Power Apps) show this text.

What this repo does today (read at objectui dd3f7e1be, objectstack's .objectui-sha)

All paths are under packages/app-shell/src/views/metadata-admin/previews/.

key ledger row (objectstack) today
app.areas[].description liveness/app.json areas.description AppPreview.tsx reads no areas at all.
permission.rowLevelSecurity[].label liveness/permission.json rowLevelSecurity.label PermissionPreview.tsx:129 reads the array, and :182 renders only a count pill (engine.permissionPreview.pill.rls).
permission.rowLevelSecurity[].description liveness/permission.json rowLevelSecurity.description Same as label: count only.
view container label liveness/view.json label ViewPreview.tsx:167 reads it into a single injected list view. But packages/plugin-view/src/ObjectView.tsx renders no tab strip for one entry (:1562, :2660), so the label never reaches the screen.

The change

  • AppPreview renders each area's description beside its label.
  • PermissionPreview lists each RLS policy with its label and description, not only the count.
  • ViewPreview shows the container label where a human sees it, for example as the preview's heading, without re-enabling a one-entry tab strip.
  • A missing value is the control in each case: nothing renders and nothing falls back to invented text.
  • Preview chrome goes through the designer locale, like the other preview strings.

⛔ Out of scope:

  • flow.description, hook.label and hook.description. ResourceListPage's default columns (defaultColumns, :626-:631) already show them, since neither type registers listColumns. The parent's ledger half cites that reader. If the parent's measurement falsifies it, the parent's seat amends this body.
  • A HookPreview, for the same reason.

Acceptance

  • Each of the four keys is visible in its preview when authored, and absent when not. A pin per preview asserts both cases.
  • Once this lands and objectstack's .objectui-sha covers the merge commit, the parent flips the four ledger rows to live, citing each preview symbol at that pin.

Dedupe: a REST listing of the 1,000 most recently updated issues in this repo (open and closed, down to #10168), grepped locally for PermissionPreview, AppPreview, HookPreview, rowLevelSecurity.label / .description, areas.description and objectstack#20299, gave 4 hits. None carries these keys: #10862 and #10880 are preview chrome locale, #7469 is AppAction, and #10570 is field-label search. The parent's seat-4 measurement 5880539559 found no carrier either.

Dedupe words: metadata-admin preview area description · PermissionPreview RLS policy label description · ViewPreview container label one-entry tab strip

Activity

  1. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: changing a running app without code — the designer shows what the author wrote | 缺项 (four authored display keys no preview renders) | P3

    Triage: first grade — enhancement · priority:p3 · domain:ui · area:studio · pm:queue. The objectui end of objectstack-ai/objectstack#20299, with its grade

    Triage: lands in packages/app-shell/src/views/metadata-admin/previews/ (AppPreview.tsx, PermissionPreview.tsx, ViewPreview.tsx) ⇒ domain:ui. It is the layer sub-issue of objectstack-ai/objectstack#20299 (p3, ENFORCE, grade 5859600931), so it takes the parent's grade.

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-29T00:54Z. ⛔ Not a claim, ⛔ not a dispatch.

    Direction: as the card states.

    • Render the four keys where a human sees them. An unauthored key renders nothing: no invented fallback text.
    • The view container label goes somewhere visible, such as the preview heading. ⛔ Don't bring back a tab strip for one entry to show it.
    • Preview chrome goes through the designer locale.
    • flow.description, hook.label / hook.description and a HookPreview stay out, as the card says: ResourceListPage's default columns already show them.
    • Pins: one per preview, with authored and absent cases.
  2. added
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    enhancementNew feature or request
    and removed on Sep 29, 2026
  3. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2 — domain:ui execution seat 2
    Session: session_011p7ikEivgXefNDaE5S5Uec
    Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11027-preview-display-keys
    Worktree: objectui-issue-11027
    Domain: domain:ui
    Seat: domain:ui#2
    File surface (triage 5881560418: as the card states):

    • packages/app-shell/src/views/metadata-admin/previews/AppPreview.tsx: each area's description beside its label.
    • packages/app-shell/src/views/metadata-admin/previews/PermissionPreview.tsx: each RLS policy is listed with its label and description, not only the count pill (:129, :182).
    • packages/app-shell/src/views/metadata-admin/previews/ViewPreview.tsx: the view container label goes somewhere visible, such as the preview heading. ⛔ Don't bring back a tab strip for one entry.
    • Preview chrome goes through the designer locale. If a label needs a new pack key, it is added to the locale packs in packages/i18n (free: seat 1's objectui#11056 has merged).
    • Pins: one per preview, with authored and absent cases (an unauthored key renders nothing: no invented fallback text). One changeset ('@object-ui/app-shell': patch, plus @object-ui/i18n if a key is added).

    ⛔ flow.description, hook.label / hook.description and a HookPreview stay out (ResourceListPage's default columns already show them). ⛔ No change to objectstack's liveness ledger (the parent objectstack-ai/objectstack#20299 keeps it).
    Stop on breach; explain in the report.
    Container & model: S, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier --repo objectstack-ai/objectui over this surface: no path-derived mandate, at objectstack 288611e3)
    Clause-②: no
    Why no: three Studio previews start rendering keys the spec already publishes; no type, schema, export or accept set moves.
    Thread-read: 5881560418
    Serial constraints cleared: read 2026-09-29T11:39Z at objectui origin/main a5841be35.


    Generated by Claude Code

  4. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 11027,
      "status": "done",
      "branch": "claude/issue-11027-preview-display-keys",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11098",
      "session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM session (container CLAUDE_CODE_REMOTE_SESSION_ID cse_011p7ikEivgXefNDaE5S5Uec); identity = branch claude/issue-11027-preview-display-keys named in PM claim 5889511891",
      "premise_still_valid": true,
      "summary": "All four display keys now render in their Studio previews, measured at origin/main a5841be35 and built on it. AppPreview had 0 areas reads (control: navigation 8 hits). It now lists AppSchema.areas: each area label and id, with the description beneath when authored. Both keys are I18nLabel, resolved in the designer locale through the spec resolveI18nLabel. PermissionPreview used rowLevelSecurity only for the count pill. It now lists each policy by name, with label and description when authored, under the existing perm.rls.title heading. The empty state now also requires rowLevelSecurity to be empty, so a policies-only set shows its policies. ViewPreview draws the view label as an h3 heading on the no-object, form and list routes. It is I18nLabel, and no one-entry tab strip was added. An unauthored key renders nothing. New chrome is one designer row, engine.appPreview.areas (en Areas, zh 区域), in metadata-admin/i18n.ts. One pin per preview covers authored and absent cases, plus locale-map cases where the key type allows one; RLS label and description are plain z.string, so they have none. The draft PR is 11098, assigned to os-support-ai; the worktree is removed.",
      "tests": "At final head 335a6c38c, all through os-verify-lock:\n(1) Build: pnpm exec turbo run build --filter=@object-ui/app-shell^... --concurrency=2 → exit 0, 28 tasks, 12 cached.\n(2) Type-check: pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) → exit 0. tsc -p tsconfig.test.json --listFilesOnly lists all 3 pins.\n(3) Tests: pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/metadata-admin/previews/ plus packages/i18n tests appDesigner-fieldDesigner-formula-retired-6310, dashboard-emptyState-keys-retired-7125 and perm-home-namespace-3546 → Test Files 82 passed (82), Tests 1108 passed (1108). That run included 1 uncommitted scratch probe (1 test), so the committed tree accounts for 81 files and 1107 tests.\n(4) Earlier, at 0edb411f1: 3 pins plus 7 sibling preview files → 10 files, 148 passed.\n(5) Reverse verification at 0edb411f1: the three preview sources were checked out at BASE a5841be35, with the pins at head. The mutation was proven on disk: each file hashed to its BASE blob, and readAreas, readPolicies and ViewLabelHeading each counted 0. Result: 11 failed, 2 passed of 13. The 2 green are the per-app no-areas and per-set no-policies absent cases, which is the expected direction. All authored, locale-map and heading cases went red, including the real object-view list route, where the base tree draws no heading for the label. Restored with git checkout HEAD under an EXIT/INT/TERM trap, proven by HEAD blob hashes and an empty git diff HEAD. The later commit 335a6c38c is type-only (draft.areas instead of an any cast; a typed stub adapter), and the reverse run was not repeated for it.\n(6) Lint narrowed to the diff: pnpm exec eslint --format json over the 7 changed ts/tsx files → 7 files, 0 errors, 29 warnings. Per-file base to head: AppPreview 8 to 8, PermissionPreview 3 to 3, ViewPreview 18 to 18, i18n.ts 0 to 0, pins 0. Population: eslint.config.js files **/*.{ts,tsx} minus the build-output ignores. Invariance: there is no parserOptions.project or projectService, so linting is not type-aware and no untouched file verdict can move. Repo-wide pnpm lint is CI.\n(7) NOT MEASURED locally: the full pnpm test and pnpm lint runs (CI), and a real browser (RTL DOM only).",
      "gates": [
        "node scripts/check-i18n-call-site-keys.mjs exit 0 @335a6c38c",
        "node scripts/check-i18n-designer-table-parity.mjs exit 0 @335a6c38c (Every en row has a zh row, and every shared row carries the same placeholders.)",
        "node scripts/check-i18n-en-drift.mjs exit 0 @335a6c38c (designer table: 1 key added, 0 en values changed)",
        "node scripts/check-changeset-presence.mjs exit 0 @335a6c38c (7 source files of 1 released package, 1 changeset)",
        "node scripts/check-changeset-no-major.mjs exit 0 @335a6c38c",
        "node scripts/check-changeset-claims.mjs exit 0 @335a6c38c (report-only; 3 pending changesets naming i18n.ts read: 6310, 7125, 8632 paragraphs still hold)",
        "node scripts/check-pending-changeset-literals.mjs exit 0 @335a6c38c",
        "node scripts/check-control-bytes.mjs exit 0 @335a6c38c",
        "node scripts/check-new-cross-file-line-citations.mjs exit 0 @335a6c38c (0 new)",
        "node scripts/check-designer-field-key-parity.mjs exit 0 @335a6c38c",
        "node scripts/check-test-path-roots.mjs exit 0 @335a6c38c",
        "pnpm --filter @object-ui/app-shell type-check exit 0 @335a6c38c",
        "pnpm exec vitest run packages/app-shell/src/views/metadata-admin/previews/ (+3 i18n designer-table readers) 82/82 files, 1108/1108 tests @335a6c38c",
        "CI snapshot at PR open: 42 check runs, 21 success, 3 skipped, 17 in_progress, 1 queued, 0 failure — in_progress; not awaited"
      ],
      "line_budget": "n/a — the diff touches no skills/** or governed surface",
      "files_changed": [
        ".changeset/11027-preview-display-keys.md",
        "packages/app-shell/src/views/metadata-admin/i18n.ts",
        "packages/app-shell/src/views/metadata-admin/previews/AppPreview.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/AppPreview.areas-11027.test.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/PermissionPreview.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/PermissionPreview.rlsPolicies-11027.test.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/ViewPreview.tsx",
        "packages/app-shell/src/views/metadata-admin/previews/ViewPreview.containerLabel-11027.test.tsx"
      ],
      "deviations": [
        "The claim and the order say a new chrome key goes into the packages/i18n locale packs. The designer engine.* rows live in the designer table (metadata-admin/i18n.ts, en and zh only, per the carve-out in packages/i18n/README.md), and that table is the only one the designer t() reads. So engine.appPreview.areas went there, and no pack changed. check:i18n-keys skips that table by declaration; check:i18n-designer-parity and check:i18n-drift are the gates that read it, and both are green.",
        "PermissionPreview empty-state condition widened by rls.length === 0, same file and same key. Without it, a policies-only set could never show its authored label or description.",
        "The first verify-2 attempt was killed by the tool timeout I wrapped around it, after the closure build had finished (exit 0) and during the type-check. The type-check was re-run on its own under the lock (exit 0). One later lock call returned 99 (queue-timeout, not measured) and was retried under the same slot.",
        "The commit trailers use the model-free pair from AGENTS.md (Claude-Session plus Co-authored-by: Claude), not the harness Co-Authored-By line that carries a model name."
      ],
      "mcp_calls": "0 — none",
      "api_writes": "3 REST writes, each packed into one relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (PR 11098, draft forced); (2) label-write --assign → POST /repos/objectstack-ai/objectui/issues/11098/assignees (os-support-ai; read back MATCHES, and no labels written by me: tests and package: app-shell came from the labeler); (3) post-stamped → POST /repos/objectstack-ai/objectui/issues/11027/comments (this report). Plus 1 git push route (branch; not REST).",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: a · reach: public door — the Studio app preview (AppPreview) renders a wrong answer for spec-valid I18nLabel maps. Measured by an uncommitted render probe at 335a6c38c; a plain-string nav label on the same mount rendered, as the control. Findings: (1) a locale-map app label prints [object Object], because the header uses String(label), and CRM is absent; (2) normalizeNav keeps a nav item label only when it is a string, so a childless nav item with a map label is dropped together with its target (Accounts and account both absent); (3) a group with a map label reads (unnamed). · evidence: every assertion in the probe passed, and each stated the observed defect state · dedupe words: AppPreview app label object Object · AppPreview navigation label locale map unnamed · app preview I18nLabel resolveI18nLabel nav label · file for the seat to raise; objectui#10862 is the next queued change on AppPreview.tsx",
        "carrier: 承接者:无 — ViewPreview still relays the view label into the one injected listView (the ledger read point), which renders nowhere on this route. Left unchanged as not this card. Noted in the PR Acceptance notes and not filed."
      ]
    }
  5. objectstack-fleet commented on Sep 29, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR objectui#11098 at 335a6c38c; ready and auto-merge follow this ACCEPT

    domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account. Claim 5889511891; dev report 5890531848; contract review 5890732852 (at CONTRACT_REVIEW_TIER, PASS, on this head).

    Implemented-by:  claude/issue-11027-preview-display-keys
    Reviewed-by:     session_011p7ikEivgXefNDaE5S5Uec
    
    item reading
    the change The four authored display keys render where a human sees them in Studio. AppPreview lists the app's areas, each with its label and, when authored, its description. PermissionPreview lists each rowLevelSecurity policy by name with its label and description, under the existing RLS heading, and keeps the count pill. ViewPreview draws the view's label as a heading on the no-object, form and list routes, with no one-entry tab strip. I18nLabel values go through the spec's resolveI18nLabel in the designer locale. An unauthored key renders nothing. Triage 5881560418 as routed
    chrome One designer-table row, engine.appPreview.areas (Areas / 区域), in metadata-admin/i18n.ts. The review measured that the designer t() reads only that table (the packages/i18n README's engine.* carve-out), so a pack key would have been unreachable. Its parity and drift gates run inside Type Check, which is green
    empty state PermissionPreview's empty message now also requires no policies. Without that, a policies-only set could never show its authored text. The review judged this required by the direction, not a widening
    tests One pin per preview, authored and absent, with locale-map cases where the key type allows one; RLS label / description are plain strings. A reverse run with the three sources at base turns 11 of 13 red; the 2 that stay green are the absent cases. previews/: 81 files / 1107 tests
    changeset '@object-ui/app-shell': patch; Clause-②: no
    CI head 335a6c38c: 40 success, 3 expected skips, 0 failure
    size 8 files, +495 / −2
    closing keywords Fixes #11027 only
    governed none of the 8 paths is on objectui's governed surfaces
    out of scope, filed objectui#11100: the app preview mis-renders a spec-valid locale-map label (the app label prints [object Object], a childless nav item with a map label is dropped, a map-label group reads (unnamed)). This is pre-existing and not made worse; this PR's new area list resolves correctly
    Acceptance notes ViewPreview still relays the label into the one injected list view, which renders nowhere on that route. This is harmless and unchanged; the direction asked for a visible heading, not for removing the relay

    domain:ui seat 2 · ACCEPT · 2026-09-29T12:57Z


    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:studioChanging a running app without code — authoring, publish, docs and the portaldomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions