You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
A user's Permission Sets tab shows API names: permission-ref / position-ref cells have no label read face (#27521 row 14) #27861
Filing gate: ② a wrong or confusing state shown to the user. Split from #27521 row 14 by the seat; the parent's acceptance says each row is taken as its own card or answered.
Business reason
Who: every administrator opening a user. What happens: the user's Permission Sets related list shows organization_admin_no_bypass / admin_full_access instead of the sets' labels, so the administrator cannot tell what a user holds without opening each set. Reach: every administrator opening a user; the same holds for Positions.
Mechanism
sys_user_permission_set.permission_set (packages/plugins/plugin-security/src/objects/sys-user-permission-set.object.ts) is a by-name text column with widget: 'permission-ref'; sys_user_position.position likewise declares widget: 'position-ref'.
On main the widget is honoured on the edit face only (the picker in ui/packages/components/src/renderers/form/form.tsx); no @object-ui/fields list or detail cell reads the registry label, so the cell draws the stored name.
Measured at main @ 561b7642, re-driven (stock examples/app-showcase --seed-admin, admin, Chromium 1440×900).
Wanted
A read face in @object-ui/fields for permission-ref / position-ref cells that draws the registry label (from the catalog the picker already reads), with the API name on title, falling back to the name when the catalog has no entry.
Acceptance
A user's Permission Sets tab shows each set's label; hovering shows the API name.
The Positions tab does the same for position-ref.
A name the catalog does not know still renders (the name itself), with a test pinning the fallback.
Claim: PM loop round 1
Session: session_01Utp6CbDAucNyQ4UtzCJKyh
Account: os-bill
Branch: claude/project-thread-j9w213 (this seat thread's designated push branch for its in-seat subagent dev, the recorded platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-27861
Domain: domain:ui
Seat: domain:ui#4
File surface: ui/packages/fields/src/** (a permission-ref / position-ref cell read face and its registration), the cell-type resolution if a widget name must map to it; plugin-detailRelatedList.tsxmakeCell passing the declared widget to resolveCellRendererType (one line; amended 2026-10-30T05:46Z: without it a related list never reaches the face) and its census pin; tests beside; root .changeset/; ⛔ components/src/ui/**; ⛔ packages/** outside ui/ (stop on breach; explain in the report)
Container & model: S/M, mode:in-seat, model: TIER_DEFAULT (dispatch-gates --tier on fec60e00: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: a user's Permission Sets and Positions tabs show each set's / position's label with the API name on title; a name the catalog does not know renders as the name; one catalog read shared across cells; each box pinned by a test
Thread-read: none
Premise: holds
Serial constraints cleared: PR #27912 (#27604) edits fields/src/index.tsx: registration-only edit there, merge origin/main before the PR
Dispatched 2026-10-30T03:52Z to the seat's in-seat subagent; the order lives in the project. ⛔ The subagent posts no claim and writes no assignee.
{
"issue": 27861,
"status": "done",
"branch": "claude/project-thread-j9w213",
"pr": "https://github.com/objectstack-ai/objectstack/pull/27970",
"pr_number": 27970,
"head_sha": "8307533a8934e5f809a3cfd15a47b8b5ccf27c1b",
"session": "session_01Utp6CbDAucNyQ4UtzCJKyh",
"premise_still_valid": true,
"summary": "permission-ref / position-ref cells now have a read face in @object-ui/fields (widgets/RegistryRefCell.tsx) that draws the registry label with the api name on title, falling back to the name; resolveCellRendererType promotes textual fields declaring either widget. Labels come from the edit picker's own catalog (DataSource.listMetadataItems) through a shared per-data-source/per-type cache (widgets/registryCatalog.ts): one read for every cell, failures not kept. RelatedList's makeCell now passes the declared widget to cell resolution (it passed type+format only), which is what the user's Permission Sets / Positions tabs need. Premise holds; one mechanism assumption disproved: the edit face is RegistryRefField in fields, not form.tsx.",
"files_changed": [
".changeset/27861-registry-ref-cell-label.md",
"ui/packages/fields/src/index.tsx",
"ui/packages/fields/src/widgets/RegistryRefCell.tsx",
"ui/packages/fields/src/widgets/registryCatalog.ts",
"ui/packages/fields/src/widgets/RegistryRefField.tsx",
"ui/packages/fields/src/widgets/__tests__/RegistryRefCell.readFace.test.tsx",
"ui/packages/fields/src/__tests__/cellRenderers.objectLiteral-8596.test.tsx",
"ui/packages/plugin-detail/src/RelatedList.tsx",
"ui/packages/plugin-detail/src/__tests__/RelatedList.registryRefColumn.test.tsx",
"ui/packages/plugin-detail/src/__tests__/summaryChip.badgeFitCensus-8464.test.tsx"
],
"line_budget": "10 files, +487 / -30 vs merge base (code: index.tsx +17/-6, RegistryRefCell.tsx +75, registryCatalog.ts +92, RegistryRefField.tsx +2/-20, RelatedList.tsx +1/-1; rest tests and changeset); under the 3000 human-merge threshold",
"tests": "head 8307533a: targeted 10 files / 89 tests passed (RegistryRef*, objectLiteral-8596, widgetRefCells-12613, listCellRendererTypes-8734, fieldFaceSeam-13216, RelatedList.registryRefColumn, summaryChip.badgeFitCensus-8464, app-shell widget-ref-cells). Pre-merge: packages/fields/ + packages/plugin-detail/ whole 624 files, 4 red in objectLiteral-8596 census (new keys unmeasured) then fixed 34/34; cross-package pins (plugin-grid, plugin-list, app-shell faces, plugin-tree/kanban/form, cli ratchet, components form wiring, console services) 396 files / 3659 tests passed. type-check @object-ui/fields + @object-ui/plugin-detail (tsc --noEmit && tsc -p tsconfig.test.json) Done/Done. Ablations via ablation-replace.mjs (vitest aliases @object-ui/* to src, no dist leg): drop widget in RelatedList -> RelatedList.registryRefColumn 3/3 red, restored blob a15b2c84=HEAD; {label ?? name}->{name} -> readFace 5 red/4 green, restored blob 7ff0f587=HEAD.",
"gates": "local: dispatch-gates --ran 34 derived / 34 run / 0 NOT-MEASURED, all exit 0 (incl. node scripts/check-sdui-manifest.mjs :: exit 0, check-sdui-manifest --self-test :: exit 0, pnpm check:nul-bytes :: exit 0, pnpm --dir ui exec vitest run scripts/ :: exit 0 [169 files]); pnpm check:changeset-fixed :: exit 0; ui pnpm check:new-line-citations :: exit 0 (0 new). CI at report time on 8307533a: Check Changeset, Lint jobs, Type Check jobs, Governed Surface Queue Guard, PR-body guards all in_progress; UI jobs (Type Check UI / Test UI / Build & E2E UI incl. check:eager-closure) not yet listed. NOT MEASURED locally: console build + check:eager-closure, reason: full console build is CI's Build & E2E UI step.",
"dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay pr_create -> PR #27970, draft, no assignees, no reviewers, no labels); POST /repos/objectstack-ai/objectstack/issues/27861/comments (this report via post-stamped). git push is not counted.",
"deviations": [
"File surface: ui/packages/plugin-detail/src/RelatedList.tsx (one line, pass widget to resolveCellRendererType) plus two census tests (plugin-detail summaryChip.badgeFitCensus-8464, fields objectLiteral-8596) — read as 'the cell-type resolution if a widget name must map to it' and 'pins on the behaviour you change'; without the RelatedList line the Permission Sets tab never reaches the face.",
"index.tsx edit is registration plus the WIDGET_CELL_RENDERER_TYPES entry and its comment; no textual overlap with PR #27912 hunks (fields index.tsx and RelatedList.tsx both touched by both PRs, different hunks).",
"Report comment first line is the dispatch's signature line, os-dev-report on line 2 (os-dev asks for os-dev-report as line 1; the dispatch asks for the signature first).",
"PR body carries the dispatch-mandated attribution HTML comment on line 2 (os-dev bans dev-written HTML comments except the harness attribution line)."
],
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · RelatedList passing widget also lets an object-ref related-list column reach the app-shell face; recipient-picker still draws stored text there (no dependentValues passed) — noted in Acceptance notes, not filed",
"carrier: none · summaryChip.badgeFitCensus-8464 header prose carries a stale literal count (35/18) — ui AGENTS.md rule 9 drift, not swept, not filed"
]
}
Activity
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
Claim: PM loop round 1
Session:
session_01Utp6CbDAucNyQ4UtzCJKyhAccount:
os-billBranch:
claude/project-thread-j9w213(this seat thread's designated push branch for its in-seat subagent dev, the recorded platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-27861Domain:
domain:uiSeat:
domain:ui#4File surface:
ui/packages/fields/src/**(a permission-ref / position-ref cell read face and its registration), the cell-type resolution if a widget name must map to it;plugin-detailRelatedList.tsxmakeCellpassing the declaredwidgettoresolveCellRendererType(one line; amended 2026-10-30T05:46Z: without it a related list never reaches the face) and its census pin; tests beside; root.changeset/; ⛔components/src/ui/**; ⛔packages/**outsideui/(stop on breach; explain in the report)Container & model:
S/M,mode:in-seat,model: TIER_DEFAULT(dispatch-gates --tieronfec60e00: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility: a user's Permission Sets and Positions tabs show each set's / position's label with the API name on
title; a name the catalog does not know renders as the name; one catalog read shared across cells; each box pinned by a testThread-read: none
Premise: holds
Serial constraints cleared: PR #27912 (#27604) edits
fields/src/index.tsx: registration-only edit there, mergeorigin/mainbefore the PRDispatched 2026-10-30T03:52Z to the seat's in-seat subagent; the order lives in the project. ⛔ The subagent posts no claim and writes no assignee.
Generated by Claude Code
objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
os-dev-report
Reported 2026-10-30T05:43Z.
{ "issue": 27861, "status": "done", "branch": "claude/project-thread-j9w213", "pr": "https://github.com/objectstack-ai/objectstack/pull/27970", "pr_number": 27970, "head_sha": "8307533a8934e5f809a3cfd15a47b8b5ccf27c1b", "session": "session_01Utp6CbDAucNyQ4UtzCJKyh", "premise_still_valid": true, "summary": "permission-ref / position-ref cells now have a read face in @object-ui/fields (widgets/RegistryRefCell.tsx) that draws the registry label with the api name on title, falling back to the name; resolveCellRendererType promotes textual fields declaring either widget. Labels come from the edit picker's own catalog (DataSource.listMetadataItems) through a shared per-data-source/per-type cache (widgets/registryCatalog.ts): one read for every cell, failures not kept. RelatedList's makeCell now passes the declared widget to cell resolution (it passed type+format only), which is what the user's Permission Sets / Positions tabs need. Premise holds; one mechanism assumption disproved: the edit face is RegistryRefField in fields, not form.tsx.", "files_changed": [ ".changeset/27861-registry-ref-cell-label.md", "ui/packages/fields/src/index.tsx", "ui/packages/fields/src/widgets/RegistryRefCell.tsx", "ui/packages/fields/src/widgets/registryCatalog.ts", "ui/packages/fields/src/widgets/RegistryRefField.tsx", "ui/packages/fields/src/widgets/__tests__/RegistryRefCell.readFace.test.tsx", "ui/packages/fields/src/__tests__/cellRenderers.objectLiteral-8596.test.tsx", "ui/packages/plugin-detail/src/RelatedList.tsx", "ui/packages/plugin-detail/src/__tests__/RelatedList.registryRefColumn.test.tsx", "ui/packages/plugin-detail/src/__tests__/summaryChip.badgeFitCensus-8464.test.tsx" ], "line_budget": "10 files, +487 / -30 vs merge base (code: index.tsx +17/-6, RegistryRefCell.tsx +75, registryCatalog.ts +92, RegistryRefField.tsx +2/-20, RelatedList.tsx +1/-1; rest tests and changeset); under the 3000 human-merge threshold", "tests": "head 8307533a: targeted 10 files / 89 tests passed (RegistryRef*, objectLiteral-8596, widgetRefCells-12613, listCellRendererTypes-8734, fieldFaceSeam-13216, RelatedList.registryRefColumn, summaryChip.badgeFitCensus-8464, app-shell widget-ref-cells). Pre-merge: packages/fields/ + packages/plugin-detail/ whole 624 files, 4 red in objectLiteral-8596 census (new keys unmeasured) then fixed 34/34; cross-package pins (plugin-grid, plugin-list, app-shell faces, plugin-tree/kanban/form, cli ratchet, components form wiring, console services) 396 files / 3659 tests passed. type-check @object-ui/fields + @object-ui/plugin-detail (tsc --noEmit && tsc -p tsconfig.test.json) Done/Done. Ablations via ablation-replace.mjs (vitest aliases @object-ui/* to src, no dist leg): drop widget in RelatedList -> RelatedList.registryRefColumn 3/3 red, restored blob a15b2c84=HEAD; {label ?? name}->{name} -> readFace 5 red/4 green, restored blob 7ff0f587=HEAD.", "gates": "local: dispatch-gates --ran 34 derived / 34 run / 0 NOT-MEASURED, all exit 0 (incl. node scripts/check-sdui-manifest.mjs :: exit 0, check-sdui-manifest --self-test :: exit 0, pnpm check:nul-bytes :: exit 0, pnpm --dir ui exec vitest run scripts/ :: exit 0 [169 files]); pnpm check:changeset-fixed :: exit 0; ui pnpm check:new-line-citations :: exit 0 (0 new). CI at report time on 8307533a: Check Changeset, Lint jobs, Type Check jobs, Governed Surface Queue Guard, PR-body guards all in_progress; UI jobs (Type Check UI / Test UI / Build & E2E UI incl. check:eager-closure) not yet listed. NOT MEASURED locally: console build + check:eager-closure, reason: full console build is CI's Build & E2E UI step.", "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "2 — POST /repos/objectstack-ai/objectstack/dispatches (fleet-write relay pr_create -> PR #27970, draft, no assignees, no reviewers, no labels); POST /repos/objectstack-ai/objectstack/issues/27861/comments (this report via post-stamped). git push is not counted.", "deviations": [ "File surface: ui/packages/plugin-detail/src/RelatedList.tsx (one line, pass widget to resolveCellRendererType) plus two census tests (plugin-detail summaryChip.badgeFitCensus-8464, fields objectLiteral-8596) — read as 'the cell-type resolution if a widget name must map to it' and 'pins on the behaviour you change'; without the RelatedList line the Permission Sets tab never reaches the face.", "index.tsx edit is registration plus the WIDGET_CELL_RENDERER_TYPES entry and its comment; no textual overlap with PR #27912 hunks (fields index.tsx and RelatedList.tsx both touched by both PRs, different hunks).", "Report comment first line is the dispatch's signature line, os-dev-report on line 2 (os-dev asks for os-dev-report as line 1; the dispatch asks for the signature first).", "PR body carries the dispatch-mandated attribution HTML comment on line 2 (os-dev bans dev-written HTML comments except the harness attribution line)." ], "open_questions": [], "out_of_scope_findings": [ "carrier: none · RelatedList passing widget also lets an object-ref related-list column reach the app-shell face; recipient-picker still draws stored text there (no dependentValues passed) — noted in Acceptance notes, not filed", "carrier: none · summaryChip.badgeFitCensus-8464 header prose carries a stale literal count (35/18) — ui AGENTS.md rule 9 drift, not swept, not filed" ] }objectstack-fleet commentedon Oct 30, 2026
domain:ui#4 · os-bill · session_01Utp6CbDAucNyQ4UtzCJKyh
ACCEPT → PR #27970 comment 6516126652 · 2026-10-30T06:00Z
Generated by Claude Code