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
ui/metadata-admin: the condition row builder offers user.role (the legacy scalar) and user.isAdmin (absent from the expression bag) as subjects, so an author builds an admin gate that never opens #28833
Filing gate: ① class (c) out-of-scope finding of the #28812 dev (os-dev-report 6565212761, out_of_scope_findings), carried to its own card by this seat. Filed by domain:server seat 5. Graded by this seat: p3 (an authoring-UI offer, no stored data moves), under 「定级你可以自己决定」 (Leehom, 2026-11-01).
Reach: any admin building a visibility or condition row in the metadata-admin inspectors who picks user.role or user.isAdmin from the subject dropdown.
Reader who acts: the lane that owns ui/packages/app-shell (domain:ui).
What the code does (read on origin/main)
ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx, CONTEXT_SUBJECTS (~line 224): record.id, user.id, user.email, user.role, user.isAdmin. The docblock above it says this list is the row builder's ONLY subject control.
The subject list offers the signals the bag actually carries: replace user.isAdmin with the real platform-admin key (measure its exact spelling in the bag), and drop or relabel user.role so it does not read as the platform role. Keep conditionScope.ts's raw-editor suggestions consistent with the builder.
Measure first whether any stored condition in examples/** or the platform apps already uses user.isAdmin or user.role; list them.
A test pins the subject list against the bag's keys, so the two cannot drift again.
Claim: PM loop round 6 · 2026-11-01T23:14Z
Session: session_01QsR2jSnzNBkkhbAQrfcS1S (card thread, os-dev); dispatched by seat session session_01QsR2jUJ19MstFvFhjgiYTu
Account: zhuangjianguo
Branch: claude/project-thread-fndqro (platform-assigned to the card thread; it can push only this branch)
Worktree: objectstack-issue-28833
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx (CONTEXT_SUBJECTS, CEL_EXAMPLE_CLAUSES), ui/packages/app-shell/src/views/metadata-admin/conditionScope.ts, their tests, and a root .changeset; ui/packages/app-shell/src/providers/ExpressionProvider.tsx is read only (stop on breach; explain in the report)
Container & model: S, mode:thread, model: default tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the condition row builder's subject list in app-shell | the expression bag ExpressionProvider builds is the source of truth for subject keys | an admin authoring a visibility or condition row who picks user.role or user.isAdmin
Thread-read: none
Premise: holds (at origin/main2a4c0034: ConditionBuilder.tsx:224CONTEXT_SUBJECTS offers user.role (:228) and user.isAdmin (:229); CEL_EXAMPLE_CLAUSES (:475) also teaches user.isAdmin)
Serial constraints cleared: domain:server#5's PR #28832 (#28812) edits ExpressionProvider.tsx's docblock; this card does not edit that file.
{
"issue": 28833,
"status": "done",
"branch": "claude/project-thread-fndqro",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28848",
"session": "session_01QsR2jSnzNBkkhbAQrfcS1S",
"premise_still_valid": true,
"summary": "CONTEXT_SUBJECTS (the row builder's default context subjects) now offers record.id, user.id, user.email and user.isPlatformAdmin: user.isAdmin, which buildExpressionUser never puts on the bag, is replaced by user.isPlatformAdmin (present on every branch, false when signed out), and user.role (the legacy better-auth scalar, `user` for a platform admin too) is dropped. CEL_EXAMPLE_CLAUSES teaches user.isPlatformAdmin. Both constants are now exported (not re-exported by the package entry). conditionScope.ts needed no edit: it names no user member (server tier gets RECORD_CONDITION_SUBJECTS, client tier inherits CONTEXT_SUBJECTS, its root lists are roots). New pin ConditionBuilder.contextSubjectsBag.test.ts evaluates every offered user.* subject against the real bag on admin, member and anonymous branches. Stored conditions: none in examples/** or platform apps; one test fixture (packages/metadata/src/__fixtures__/hotcrm-17.1-built-bare-root-predicates.artifact.json, current_user.role == \"admin\"). Measurement differing from the card: a fault on user.isAdmin never opens on action and navigation gates (fail-closed / withhold) but opens for everyone on an object field visible via evaluateVisibility (documented fail-open policy); corrected wording is in the PR body.",
"tests": "At 457b72bb (main 892eb668 merged): git grep -l set of app-shell tests naming ConditionBuilder / conditionScope / CONTEXT_SUBJECTS / celExampleForRoots / buildExpressionUser, --maxWorkers=2 under os-verify-lock: Test Files 60 passed (60), Tests 667 passed (667). At 8f66ea84: 53 files, 611 passed. Ablation via scripts/ablation-replace.mjs at 8f66ea84 (source-resolved, no dist): user.isAdmin re-added to CONTEXT_SUBJECTS -> 3 failed / 5 passed (expected [ 'id', 'name', 'email', 'role', ...(2) ] to include 'isAdmin'); CEL_EXAMPLE_CLAUSES back to user.isAdmin -> 1 failed / 7 passed; both restored, blob 90d12c3f == HEAD, git diff HEAD empty. pnpm --filter @object-ui/app-shell run type-check: exit 0 at 457b72bb and 8f66ea84. ESLint on 5 changed files: 0 errors (two new react-refresh/only-export-components warnings on the exported constants, same class as the file's existing ones).",
"gates": "dispatch-gates --commands at 457b72bb: 34 derived, 34 run, each exit 0 (check:type-check-debt under the lock; PR-body gates with the final body as GITHUB_EVENT_PATH); --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Same 34/34 at 8f66ea84. check-partof-closing-keyword with PR_BODY: exit 0. CI at pr_create: 17 in_progress, 3 skipped, 0 failed.",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"mcp_calls": "0",
"api_writes": "3 — git push x2 (branch), fleet-write pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> pulls #28848, read-back identical 7597 bytes), plus this report comment through post-stamped",
"deviations": "No assignee or reviewer on the PR (os-dev rule 2; the harness asks for one, the dispatch contract wins). No PR subscription (dispatch contract over the platform's subscription posture). Merge commit 457b72bb carries git's default message.",
"open_questions": [],
"out_of_scope_findings": [
"carrier: none · noted, not filed — evaluateVisibility (object field visible) fails open on a faulting predicate; documented deliberate policy (objectui#6443 / #6487 / #6445, evaluateVisibility and expressionUser.ts docblocks), so not a finding. No stored or authored row in examples/** or platform apps names user.isAdmin, so none opens for everyone today.",
"carrier: none · noted, not filed — the bag also carries user.name and user.positions, which the row builder does not offer; adding subjects is outside this card."
]
}
Landed · 2026-11-02T01:06Z · PR #28848 merged through the merge queue as a3143182 at 2026-11-02T01:05:56Z (GitHub's clock). ACCEPT 6566362328 at head 457b72bb.
probe
before (a3143182~1)
now (origin/main)
'user.isAdmin' literals in inspectors/ConditionBuilder.tsx
Activity
objectstack-fleet commentedon Nov 1, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu
Claim: PM loop round 6 · 2026-11-01T23:14Z
Session:
session_01QsR2jSnzNBkkhbAQrfcS1S(card thread, os-dev); dispatched by seat sessionsession_01QsR2jUJ19MstFvFhjgiYTuAccount:
zhuangjianguoBranch:
claude/project-thread-fndqro(platform-assigned to the card thread; it can push only this branch)Worktree:
objectstack-issue-28833Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/app-shell/src/views/metadata-admin/inspectors/ConditionBuilder.tsx(CONTEXT_SUBJECTS,CEL_EXAMPLE_CLAUSES),ui/packages/app-shell/src/views/metadata-admin/conditionScope.ts, their tests, and a root.changeset;ui/packages/app-shell/src/providers/ExpressionProvider.tsxis read only (stop on breach; explain in the report)Container & model: S,
mode:thread,model: default tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the condition row builder's subject list in app-shell | the expression bag ExpressionProvider builds is the source of truth for subject keys | an admin authoring a visibility or condition row who picks user.role or user.isAdminThread-read: none
Premise: holds (at
origin/main2a4c0034:ConditionBuilder.tsx:224CONTEXT_SUBJECTSoffersuser.role(:228) anduser.isAdmin(:229);CEL_EXAMPLE_CLAUSES(:475) also teachesuser.isAdmin)Serial constraints cleared:
domain:server#5's PR #28832 (#28812) editsExpressionProvider.tsx's docblock; this card does not edit that file.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jSnzNBkkhbAQrfcS1S
os-dev-report
{ "issue": 28833, "status": "done", "branch": "claude/project-thread-fndqro", "pr": "https://github.com/objectstack-ai/objectstack/pull/28848", "session": "session_01QsR2jSnzNBkkhbAQrfcS1S", "premise_still_valid": true, "summary": "CONTEXT_SUBJECTS (the row builder's default context subjects) now offers record.id, user.id, user.email and user.isPlatformAdmin: user.isAdmin, which buildExpressionUser never puts on the bag, is replaced by user.isPlatformAdmin (present on every branch, false when signed out), and user.role (the legacy better-auth scalar, `user` for a platform admin too) is dropped. CEL_EXAMPLE_CLAUSES teaches user.isPlatformAdmin. Both constants are now exported (not re-exported by the package entry). conditionScope.ts needed no edit: it names no user member (server tier gets RECORD_CONDITION_SUBJECTS, client tier inherits CONTEXT_SUBJECTS, its root lists are roots). New pin ConditionBuilder.contextSubjectsBag.test.ts evaluates every offered user.* subject against the real bag on admin, member and anonymous branches. Stored conditions: none in examples/** or platform apps; one test fixture (packages/metadata/src/__fixtures__/hotcrm-17.1-built-bare-root-predicates.artifact.json, current_user.role == \"admin\"). Measurement differing from the card: a fault on user.isAdmin never opens on action and navigation gates (fail-closed / withhold) but opens for everyone on an object field visible via evaluateVisibility (documented fail-open policy); corrected wording is in the PR body.", "tests": "At 457b72bb (main 892eb668 merged): git grep -l set of app-shell tests naming ConditionBuilder / conditionScope / CONTEXT_SUBJECTS / celExampleForRoots / buildExpressionUser, --maxWorkers=2 under os-verify-lock: Test Files 60 passed (60), Tests 667 passed (667). At 8f66ea84: 53 files, 611 passed. Ablation via scripts/ablation-replace.mjs at 8f66ea84 (source-resolved, no dist): user.isAdmin re-added to CONTEXT_SUBJECTS -> 3 failed / 5 passed (expected [ 'id', 'name', 'email', 'role', ...(2) ] to include 'isAdmin'); CEL_EXAMPLE_CLAUSES back to user.isAdmin -> 1 failed / 7 passed; both restored, blob 90d12c3f == HEAD, git diff HEAD empty. pnpm --filter @object-ui/app-shell run type-check: exit 0 at 457b72bb and 8f66ea84. ESLint on 5 changed files: 0 errors (two new react-refresh/only-export-components warnings on the exported constants, same class as the file's existing ones).", "gates": "dispatch-gates --commands at 457b72bb: 34 derived, 34 run, each exit 0 (check:type-check-debt under the lock; PR-body gates with the final body as GITHUB_EVENT_PATH); --ran: 34 derived, 34 run, 0 NOT-MEASURED, 0 UNRUN. Same 34/34 at 8f66ea84. check-partof-closing-keyword with PR_BODY: exit 0. CI at pr_create: 17 in_progress, 3 skipped, 0 failed.", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "mcp_calls": "0", "api_writes": "3 — git push x2 (branch), fleet-write pr_create (POST /repos/objectstack-ai/objectstack/dispatches -> pulls #28848, read-back identical 7597 bytes), plus this report comment through post-stamped", "deviations": "No assignee or reviewer on the PR (os-dev rule 2; the harness asks for one, the dispatch contract wins). No PR subscription (dispatch contract over the platform's subscription posture). Merge commit 457b72bb carries git's default message.", "open_questions": [], "out_of_scope_findings": [ "carrier: none · noted, not filed — evaluateVisibility (object field visible) fails open on a faulting predicate; documented deliberate policy (objectui#6443 / #6487 / #6445, evaluateVisibility and expressionUser.ts docblocks), so not a finding. No stored or authored row in examples/** or platform apps names user.isAdmin, so none opens for everyone today.", "carrier: none · noted, not filed — the bag also carries user.name and user.positions, which the row builder does not offer; adding subjects is outside this card." ] }objectstack-fleet commentedon Nov 2, 2026
domain:ui#1 · zhuangjianguo · session_01QsR2jUJ19MstFvFhjgiYTu
Landed · 2026-11-02T01:06Z · PR #28848 merged through the merge queue as
a3143182at 2026-11-02T01:05:56Z (GitHub's clock). ACCEPT 6566362328 at head457b72bb.a3143182~1)origin/main)'user.isAdmin'literals ininspectors/ConditionBuilder.tsxinspectors/ConditionBuilder.contextSubjectsBag.test.tsexistsFixes #28833closed this card.pm:dispatchedcomes off in the same stroke as this note.Generated by Claude Code