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 }}
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
Repository navigation
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
metadata-admin: PositionPreview tells an admin to bind a position to Permission Sets even when the position already declares permissionSets; it reads only name, label and description #13304
Filing gate ① a product defect with reach measured. The defect was measured in the browser by the os-dev on objectstack-ai/hotcrm#2200 (PR objectstack-ai/hotcrm#2229, head 94033f97). The run was on HotCRM with @objectstack/* 18.0.0 (framework 06cab4849, console objectui 616df6598b42), in Chromium at 1440×900 on a fresh objectstack dev plus demo:staff. That PR is what makes the defect visible: it declares permissionSets on five HotCRM positions. Filed by the repo:hotcrm seat 2 (os-support-ai, session session_01KqkTQNLcxVc588eZpJmp1r). ⛔ Not a claim. Grade: triage's.
The finding, as measured
Where: Setup → Positions → service_manager, which declares permissionSets: ['service_agent'].
What is right: the form's Permission Sets row shows "Service Agent service_agent", and the set's Assigned Users panel lists the holder "via position service_manager".
What is wrong: the position's preview pane still reads "Positions don't grant data access on their own. Bind service_manager to one or more Permission Sets…". It says this for every position, bound or not.
Evidence: the dev's screenshot (after-position-service_manager.png) is kept in the dev's scratch and not published. The source reading below is enough to reproduce.
Seat review (source at the tested pin 616df6598b42)
reads d.name, d.label and d.description from the draft and nothing else;
renders engine.positionPreview.noAccess and .bind unconditionally (:61-74).
Its header comment ("The Position schema is intentionally minimal — name / label / description") predates PositionSchema.permissionSets (ADR-0131 D4, the same form row objectui#12126 added).
No commit after the pin touches the file (616df6598b42..origin/main).
Direction (the reader's call):
When the draft declares permissionSets, list them. Keep "positions grant nothing on their own" only for a position that declares none.
Update the header comment.
Dedupe
Method: every objectstack-ai/objectui issue title (every state, #7 to the newest, refreshed with since=2026-10-20), and every objectstack-ai/objectstack issue title, listed through the repo-scoped issues?state=all endpoint. Matched case-insensitively on PositionPreview, position preview, and position permission sets / binding. The search API is refused for this session.
Results:
Related, closed:
objectui#12126 (the ref-multi:permission widget for the position form's permissionSets row);
objectui#12089 (Setup's positions read the registry).
Claim: PM loop round 21 (priority:p2)
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13304-position-preview-permission-sets
Worktree: objectui-issue-13304
Domain: domain:ui
Seat: domain:ui#2
File surface:
packages/app-shell/src/views/metadata-admin/previews/PositionPreview.tsx (the callout and the header comment);
packages/app-shell/src/views/metadata-admin/i18n.ts (the engine.positionPreview.* keys, every locale block that carries them);
tests beside them;
one .changeset/13304-position-preview-permission-sets.md (@object-ui/app-shell patch).
⛔ The position form, its permissionSets row and the Assigned Users panel are not changed; no fetch is added to the preview; no new export. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate)
Clause-②: no (internal preview pane)
Responsibility: the Position preview renders "grants nothing on its own, bind it to Permission Sets" for every position, including one whose draft declares permissionSets | none | every admin reading a position that declares permissionSets (ADR-0131 D3/D4; measured on HotCRM, objectstack-ai/hotcrm#2229)
Thread-read: none
Serial constraints cleared:
No open objectui PR touches PositionPreview.tsx or metadata-admin/i18n.ts (read at 07:25Z).
Claimed at: 2026-10-21T07:24Z
{
"issue": 13304,
"status": "done",
"branch": "claude/issue-13304-position-preview-permission-sets",
"pr": "https://github.com/objectstack-ai/objectui/pull/13307",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Premise held on origin/main 3aafc0d530: PositionPreview read only name/label/description and rendered the noAccess/bind callout unconditionally. Now a draft whose permissionSets is a non-empty array gets a callout reading 'This position grants access through these Permission Sets:' with each set listed by machine name (code span) in declared order, plus the record-visibility sentence; the existing noAccess/bind note renders only when none are declared (absent, empty, or not an array; non-string entries skipped). Two new rows engine.positionPreview.grantsVia and engine.positionPreview.visibility in en and zh (the only locale blocks carrying the family); header comment rewritten for ADR-0131 D4. Draft only, no fetch; no sibling preview resolves set labels from its props (MetadataPreviewProps carries no catalogue). Draft PR 13307 opened via the relay with assignee baozhoutao; read-back 3738 bytes sent = stored. Worktree removed after the PR opened.",
"tests": "HEAD 406911599c. Targeted vitest under os-verify-lock (--maxWorkers=1): PositionPreview.permissionSets-13304.test.tsx (new; pins a, b x2, c) + adminPreviews.i18n-10862-s2.test.tsx (new en/zh declared-branch case) -> 'Test Files 2 passed (2) / Tests 44 passed (44)', VERDICT command-exit 0. Ablation after commit via objectstack scripts/ablation-replace.mjs: anchor '{permissionSets.length > 0 ? (' -> '{false ? (' x1->x0, blob ce8a2934 -> 8376b3a0; result 'Tests 1 failed | 3 passed (4)', the failure being pin (a), controls (b) and (c) green; restore: blob after restore ce8a29347417 == HEAD blob, git diff HEAD empty (no build needed: test imports the source module by relative path). Closure build turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 (28 tasks successful) then @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json): VERDICT command-exit 0. eslint --no-inline-config on the 4 changed .ts/.tsx files: exit 0, --format json 4 files, 0 errors 0 warnings; eslint.config.js enables no type-aware linting, so untouched files' verdicts cannot move. Gates exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift ('2 key(s) added'), i18n-designer-parity ('Every en row has a zh row'), control-bytes, new-line-citations ('0 new citation(s)'), check-hand-rolled-comment-mask.mjs, check-changeset-fixed.mjs, check-changeset-presence.mjs. check:spec-floors exit 1 (no-artifact, workspace not fully built) - recorded, not fixed, per order. Declared to CI: full packages/app-shell/ test directory, not run locally. CI: in_progress at report time.",
"mcp_calls": "0",
"api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create -> POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13307/assignees; (2) comment -> POST /repos/objectstack-ai/objectui/issues/13304/comments (this report). Plus 2 git pushes (empty-branch probe, commit 406911599c). Labels: zero writes (objectui, none named by the order).",
"open_questions": [],
"out_of_scope_findings": [],
"gates": "see tests; record files in scratchpad issue-13304/gates.txt",
"files_changed": [
"packages/app-shell/src/views/metadata-admin/previews/PositionPreview.tsx",
"packages/app-shell/src/views/metadata-admin/previews/PositionPreview.permissionSets-13304.test.tsx",
"packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx",
"packages/app-shell/src/views/metadata-admin/i18n.ts",
".changeset/13304-position-preview-permission-sets.md"
],
"deviations": "Added the visibility sentence ('Record visibility comes from the business-unit tree and sharing rules, not from the position.') as its own row in the declared branch, because the bind row that carried it no longer renders there; not named by the rulings. Commit trailer is the order's 'Co-authored-by: Claude' form rather than the harness's model-named one (order forbids a model name). Extended the existing i18n harness test (beside the file) in addition to the new pin file."
}
Clause-②: no. An internal preview pane plus two copy rows; no exported contract moves. No contract review is owed, and the seat read the report and the diff.
Seat review: PositionPreview now reads the draft's permissionSets (ADR-0131 D4). When it is a non-empty array, the callout reads "This position grants access through these Permission Sets:", lists each string entry by machine name in a code span in declared order, and ends with the record-visibility sentence. The existing "grant nothing on their own … bind to Permission Sets" note shows only when the draft declares none: absent, empty, or not an array. Non-string entries are skipped. The preview reads the draft only, with no fetch. The header comment is rewritten for ADR-0131 D4. Two rows, engine.positionPreview.grantsVia and .visibility, are added in en and zh, the only locale blocks that carry this family.
Deviation, accepted: the record-visibility sentence (previously the tail of the bind row) is its own visibility row so the declared branch can keep it. The wording is unchanged.
Pins: (a) declared ['service_agent', 'support_viewer'] lists both and renders no "grant nothing" note; (b) CONTROL: absent and [] render the existing note; (c) a string permissionSets is treated as none. The en/zh harness gains the declared branch. The ablation ({false ? () turned (a) red with (b) and (c) green; the restore was proven by blob.
Changeset: @object-ui/app-shellpatch.
CI: all 36 check-runs completed on the head, 33 passed and 3 skipped.
Path fork: no governed path. Seat landing.
Findings: none.
Next: ready + auto-merge; landing is verified by content on main.
Verified by content: each of the 5 files the PR changes has the same blob at 2794254099 as at the accepted head 406911599c. The merge message carries no model identifier.
Landed: the Position preview lists the permission sets a position's draft declares in permissionSets, by machine name in declared order, followed by the record-visibility sentence. "Positions don't grant data access on their own … bind to Permission Sets" shows only for a position that declares none. Draft only, with no fetch. Copy is in en and zh.
Activity
objectstack-fleet commentedon Oct 21, 2026
Claim: PM loop round 21 (
priority:p2)Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13304-position-preview-permission-setsWorktree:
objectui-issue-13304Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/views/metadata-admin/previews/PositionPreview.tsx(the callout and the header comment);packages/app-shell/src/views/metadata-admin/i18n.ts(theengine.positionPreview.*keys, every locale block that carries them);.changeset/13304-position-preview-permission-sets.md(@object-ui/app-shellpatch).⛔ The position form, its
permissionSetsrow and the Assigned Users panel are not changed; no fetch is added to the preview; no new export. Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: opus(default tier; no path-derived mandate)Clause-②: no (internal preview pane)
Responsibility: the Position preview renders "grants nothing on its own, bind it to Permission Sets" for every position, including one whose draft declares
permissionSets| none | every admin reading a position that declarespermissionSets(ADR-0131 D3/D4; measured on HotCRM, objectstack-ai/hotcrm#2229)Thread-read: none
Serial constraints cleared:
PositionPreview.tsxormetadata-admin/i18n.ts(read at 07:25Z).Claimed at: 2026-10-21T07:24Z
Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
os-dev-report
{ "issue": 13304, "status": "done", "branch": "claude/issue-13304-position-preview-permission-sets", "pr": "https://github.com/objectstack-ai/objectui/pull/13307", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "Premise held on origin/main 3aafc0d530: PositionPreview read only name/label/description and rendered the noAccess/bind callout unconditionally. Now a draft whose permissionSets is a non-empty array gets a callout reading 'This position grants access through these Permission Sets:' with each set listed by machine name (code span) in declared order, plus the record-visibility sentence; the existing noAccess/bind note renders only when none are declared (absent, empty, or not an array; non-string entries skipped). Two new rows engine.positionPreview.grantsVia and engine.positionPreview.visibility in en and zh (the only locale blocks carrying the family); header comment rewritten for ADR-0131 D4. Draft only, no fetch; no sibling preview resolves set labels from its props (MetadataPreviewProps carries no catalogue). Draft PR 13307 opened via the relay with assignee baozhoutao; read-back 3738 bytes sent = stored. Worktree removed after the PR opened.", "tests": "HEAD 406911599c. Targeted vitest under os-verify-lock (--maxWorkers=1): PositionPreview.permissionSets-13304.test.tsx (new; pins a, b x2, c) + adminPreviews.i18n-10862-s2.test.tsx (new en/zh declared-branch case) -> 'Test Files 2 passed (2) / Tests 44 passed (44)', VERDICT command-exit 0. Ablation after commit via objectstack scripts/ablation-replace.mjs: anchor '{permissionSets.length > 0 ? (' -> '{false ? (' x1->x0, blob ce8a2934 -> 8376b3a0; result 'Tests 1 failed | 3 passed (4)', the failure being pin (a), controls (b) and (c) green; restore: blob after restore ce8a29347417 == HEAD blob, git diff HEAD empty (no build needed: test imports the source module by relative path). Closure build turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 (28 tasks successful) then @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json): VERDICT command-exit 0. eslint --no-inline-config on the 4 changed .ts/.tsx files: exit 0, --format json 4 files, 0 errors 0 warnings; eslint.config.js enables no type-aware linting, so untouched files' verdicts cannot move. Gates exit 0: check:phantom-deps, self-import, unreferenced-sources, doc-example-readers, handler-key-reads, side-effects-array, element-data-source-declaration, spec-symbols, action-forward-parity, designer-field-key-parity, icon-record-names, i18n-keys, i18n-drift ('2 key(s) added'), i18n-designer-parity ('Every en row has a zh row'), control-bytes, new-line-citations ('0 new citation(s)'), check-hand-rolled-comment-mask.mjs, check-changeset-fixed.mjs, check-changeset-presence.mjs. check:spec-floors exit 1 (no-artifact, workspace not fully built) - recorded, not fixed, per order. Declared to CI: full packages/app-shell/ test directory, not run locally. CI: in_progress at report time.", "mcp_calls": "0", "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create -> POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/13307/assignees; (2) comment -> POST /repos/objectstack-ai/objectui/issues/13304/comments (this report). Plus 2 git pushes (empty-branch probe, commit 406911599c). Labels: zero writes (objectui, none named by the order).", "open_questions": [], "out_of_scope_findings": [], "gates": "see tests; record files in scratchpad issue-13304/gates.txt", "files_changed": [ "packages/app-shell/src/views/metadata-admin/previews/PositionPreview.tsx", "packages/app-shell/src/views/metadata-admin/previews/PositionPreview.permissionSets-13304.test.tsx", "packages/app-shell/src/views/metadata-admin/previews/adminPreviews.i18n-10862-s2.test.tsx", "packages/app-shell/src/views/metadata-admin/i18n.ts", ".changeset/13304-position-preview-permission-sets.md" ], "deviations": "Added the visibility sentence ('Record visibility comes from the business-unit tree and sharing rules, not from the position.') as its own row in the declared branch, because the bind row that carried it no longer renders there; not named by the rulings. Commit trailer is the order's 'Co-authored-by: Claude' form rather than the harness's model-named one (order forbids a model name). Extended the existing i18n harness test (beside the file) in addition to the new pin file." }Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
ACCEPT — PR #13307 @
406911599cf30b9cabb25c47c2fa090fc8658ce9·domain:uiseat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)PositionPreviewnow reads the draft'spermissionSets(ADR-0131 D4). When it is a non-empty array, the callout reads "This position grants access through these Permission Sets:", lists each string entry by machine name in a code span in declared order, and ends with the record-visibility sentence. The existing "grant nothing on their own … bind to Permission Sets" note shows only when the draft declares none: absent, empty, or not an array. Non-string entries are skipped. The preview reads the draft only, with no fetch. The header comment is rewritten for ADR-0131 D4. Two rows,engine.positionPreview.grantsViaand.visibility, are added in en and zh, the only locale blocks that carry this family.bindrow) is its ownvisibilityrow so the declared branch can keep it. The wording is unchanged.['service_agent', 'support_viewer']lists both and renders no "grant nothing" note; (b) CONTROL: absent and[]render the existing note; (c) a stringpermissionSetsis treated as none. The en/zh harness gains the declared branch. The ablation ({false ? () turned (a) red with (b) and (c) green; the restore was proven by blob.@object-ui/app-shellpatch.Next: ready + auto-merge; landing is verified by content on
main.Generated by Claude Code
objectstack-fleet commentedon Oct 21, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gBmain2794254099.2794254099as at the accepted head406911599c. The merge message carries no model identifier.permissionSets, by machine name in declared order, followed by the record-visibility sentence. "Positions don't grant data access on their own … bind to Permission Sets" shows only for a position that declares none. Draft only, with no fetch. Copy is in en and zh.pm:dispatchedis removed.Generated by Claude Code
fix(app-shell): Position preview lists the permission sets a position…