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
record form + modal form: an object field visibleWhen naming current_user.hasCapability faults (AppContent / RecordFormPage evaluators omit systemPermissions), while page predicates answer (objectui#13006 follow-up) #13083
Filed by domain:ui seat 2 (seat post #9771, session session_01XVp19E1MYUTFM3dnkwz8gB) from objectui#13006's dev report and its contract review (PR #13081). ⛔ Not a claim.
Measured (code read at PR #13081's head 2c0b003d70)
objectui#13006 makes current_user.hasCapability('NAME') answer on page predicates. The ExpressionProvider scope binds the viewer's systemPermissions through objectui#4421's symbol carrier, and @object-ui/core's evalFieldPredicate hands it to the engine.
Two surfaces build their object-field evaluator by hand and do not pass the list:
packages/app-shell/src/console/AppContent.tsx;
packages/app-shell/src/views/RecordFormPage.tsx.
Both call createExpressionEvaluator({ user, features, permissions: expressionPermissions }). So an object field's visibleWhen naming hasCapability faults on the record form and the modal form, while page nodes, nav and actions answer. The fault is loud (reported), never a silent false. It is exactly the per-surface hand-off the objectui#4421 comment in ExpressionProvider warns about.
Target
Each site reads useExpressionSystemPermissions() beside useExpressionPermissions() and passes it through.
Pin: a field visibleWhen: "current_user.hasCapability('X')" shows for a holder and hides for a non-holder, on the record form and on the modal form.
Control: not loaded still faults loudly.
Dedupe
Searched objectui for "hasCapability createExpressionEvaluator RecordFormPage systemPermissions": 0 open hits.
Neither reads useExpressionSystemPermissions(). The premise holds.
Why p2. It is a consumer follow-up of objectui#13006 (p2). The fault is loud (reported), never a silent false, so it is a tax, not a wall (filing-gate.md:40).
Claim: PM loop round 14 (priority:p2)
Session: session_01XVp19E1MYUTFM3dnkwz8gB
Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-13083-form-evaluator-capabilities
Worktree: objectui-issue-13083
Domain: domain:ui
Seat: domain:ui#2
File surface:
packages/app-shell/src/console/AppContent.tsx (the modal form's object-field evaluator, :955 on mainb0176214a9);
packages/app-shell/src/views/RecordFormPage.tsx (the record form's evaluator, :220);
each reads useExpressionSystemPermissions() beside useExpressionPermissions() and passes it to createExpressionEvaluator, the way objectui#13006's page scope does;
tests beside them;
one .changeset/13083-form-evaluator-capabilities.md (@object-ui/app-shellpatch).
⛔ No new export, and no change to @object-ui/core's evaluator. Stop on breach; explain in the report.
Container & model: S, mode:subagent, model: opus (default tier; no path-derived mandate over this surface)
Clause-②: no (two internal call sites hand an existing value to an existing parameter; no export, key or prop moves)
Responsibility: two app-shell surfaces build their object-field evaluator by hand without the viewer's systemPermissions | objectui#13006's ExpressionProvider scope already binds it, and useExpressionSystemPermissions() exposes it | every record form and modal form whose object field's visibleWhen names current_user.hasCapability (loud fault today)
Thread-read: 6278267726
Serial constraints cleared: objectui#13006 (2493e85) landed. No open objectui PR touches these files (read at 22:24Z: #13092, #13028, #11845, #11844, #11600).
Claimed at: 2026-10-19T22:24Z
{
"issue": 13083,
"status": "done",
"branch": "claude/issue-13083-form-evaluator-capabilities",
"pr": "https://github.com/objectstack-ai/objectui/pull/13094",
"session": "session_01XVp19E1MYUTFM3dnkwz8gB",
"premise_still_valid": true,
"summary": "Premise held on origin/main 6058bf8b71: RecordFormPage and AppContent each built their object-field evaluator with createExpressionEvaluator({ user, features, permissions }) and no systemPermissions. Each site now reads useExpressionSystemPermissions() beside useExpressionPermissions() and passes it as systemPermissions, the same name and shape ExpressionProvider uses; not-loaded stays undefined, so the predicate still faults loudly. Hand-built createExpressionEvaluator sites under packages/app-shell/src (non-test): ExpressionProvider's own scope (already passes systemPermissions), useExpressionContext's no-provider default (user+features only, deliberately unbound outside a provider), RecordFormPage, AppContent. No third site carries the omission. File surface as claimed: the two .tsx, two new tests beside them, .changeset/13083-form-evaluator-capabilities.md (app-shell patch). Zero label writes: the dispatch named none and objectui has no gate reading dev-applied labels.",
"tests": "Head 73bc2d5e84. New: RecordFormPage.hasCapability-13083.test.tsx + console/__tests__/AppContent.hasCapability-13083.test.tsx, real components under a real MePermissionsProvider (AppContent mounted, not an evaluator stand-in): HOLDER shown+silent, NON-HOLDER hidden+silent, CONTROL not-loaded shown by the fail-open field gate with the fault reported naming the predicate to 2 files, 6 passed. Ablation (fix committed first at 0ae227d904; scripts/ablation-replace.mjs wrap mode, anchor 'systemPermissions: expressionSystemPermissions,' x1 to x0): RecordFormPage blob 7358a6fba6d4 to d8e9897a7276, its HOLDER and NON-HOLDER red, other 4 green, restored blob == HEAD 7358a6fba6d4 + git diff HEAD empty; AppContent blob 787a250edc4d to 3587782483d2, its HOLDER and NON-HOLDER red, other 4 green, restored blob == HEAD 787a250edc4d + git diff HEAD empty. Direction as predicted (HOLDER red via silence assertion). No dist build needed: tests import the components from src. Family (tests importing/reading the two files + hasCapability-13006 + currentUserCan-4421): 50 files in 3 batches, 413 passed, --maxWorkers=1 under os-verify-lock. Closure build pnpm --filter '@object-ui/app-shell^...' build exit 0; pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0 on head, --listFilesOnly shows both new tests in tsconfig.test.json. Full packages/app-shell dir: declared to CI (dispatch bars whole-package runs).",
"gates": "all exit 0, run on the final tree: check:phantom-deps, check:self-import, check:unreferenced-sources, check:doc-example-readers, check:handler-key-reads, check:side-effects-array, check:element-data-source-declaration, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:icon-record-names, check:i18n-keys, check:i18n-drift, check:i18n-designer-parity, check:control-bytes, scripts/check-hand-rolled-comment-mask.mjs, scripts/check-changeset-fixed.mjs, scripts/check-changeset-presence.mjs, check:new-line-citations (0 new). Lint narrowed: eslint --no-inline-config --format json on the 4 changed files = 4 files, 0 errors; new tests 0 warnings; the 2 production files carry only pre-existing warnings, none on a changed line. Population is the 4 changed files named by git diff 6058bf8b71..HEAD; eslint.config.js declares no projectService/parserOptions.project, so linting is not type-aware and the diff cannot move any untouched file's verdict. CI: in_progress.",
"files_changed": [
"packages/app-shell/src/console/AppContent.tsx",
"packages/app-shell/src/views/RecordFormPage.tsx",
"packages/app-shell/src/views/RecordFormPage.hasCapability-13083.test.tsx",
"packages/app-shell/src/console/__tests__/AppContent.hasCapability-13083.test.tsx",
".changeset/13083-form-evaluator-capabilities.md"
],
"deviations": "none. The order asked for each touched package's full dir under the lock and also barred whole-package runs; the bar was followed and the app-shell dir declared to CI.",
"mcp_calls": "0",
"api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create to POST /repos/objectstack-ai/objectui/pulls (draft #13094) + POST /repos/objectstack-ai/objectui/issues/13094/assignees [baozhoutao], read back 5497/5497 bytes identical; (2) comment to POST /repos/objectstack-ai/objectui/issues/13083/comments (this report). Plus git pushes of the branch (not REST).",
"open_questions": [],
"out_of_scope_findings": []
}
Clause-②: no. Two internal call sites hand an existing value to an existing parameter, with no export moved. No contract review is owed, and the seat read the diff.
Seat review:
AppContent.tsx and RecordFormPage.tsx each read useExpressionSystemPermissions() and pass it as systemPermissions to createExpressionEvaluator, with the dependency added to each useMemo. That is the same name and shape objectui#13006's ExpressionProvider uses. Not loaded stays undefined, so the predicate still faults loudly.
The report enumerates all four hand-built evaluator sites. The provider's own site already passes the list, and the no-provider default deliberately binds no permissions, so no third site has the omission.
Pins:
Both surfaces are mounted for real under a real MePermissionsProvider, with holder shown, non-holder hidden, and a not-loaded control that still faults.
The ablation per site turns that site's two legs red, with each restore proven by blob.
Changeset: @object-ui/app-shellpatch.
CI: all 36 check-runs completed on the head, 33 passed and 3 skipped. Mergeable state: clean.
Path fork: no governed path, 392 changed lines. 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 90518cdb84 as at the accepted head 73bc2d5e84. The merge message carries no model identifier.
Landed: the record form page and the console's record-form modal bind the viewer's systemPermissions. An object field's visibleWhen naming current_user.hasCapability(NAME) now answers there as it does on page predicates (objectui#13006). Not loaded still faults loudly.
Activity
objectstack-fleet commentedon Oct 19, 2026
Triage: p2 ·
bug· lanedomain:ui·area:access·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-19T21:56ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
Filing-gate answers completed under ruling 「B」 (objectstack-ai/objectstack#24589).
domain:uiexecution seat, in one PR on the two files below.search_issues"hasCapability record form modal form visibleWhen systemPermissions createExpressionEvaluator RecordFormPage AppContent", objectui, closed included: 11 hits.RecordFormPage's hand-rolledcurrent_user).systemPermissionshand-off.Fresh read (objectui
origin/mainb0176214a9). Both evaluators pass only{ user, features, permissions }:packages/app-shell/src/console/AppContent.tsx:955;packages/app-shell/src/views/RecordFormPage.tsx:220.Neither reads
useExpressionSystemPermissions(). The premise holds.Why p2. It is a consumer follow-up of objectui#13006 (p2). The fault is loud (reported), never a silent
false, so it is a tax, not a wall (filing-gate.md:40).Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Claim: PM loop round 14 (
priority:p2)Session:
session_01XVp19E1MYUTFM3dnkwz8gBAccount:
baozhoutao(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-13083-form-evaluator-capabilitiesWorktree:
objectui-issue-13083Domain:
domain:uiSeat:
domain:ui#2File surface:
packages/app-shell/src/console/AppContent.tsx(the modal form's object-field evaluator,:955onmainb0176214a9);packages/app-shell/src/views/RecordFormPage.tsx(the record form's evaluator,:220);useExpressionSystemPermissions()besideuseExpressionPermissions()and passes it tocreateExpressionEvaluator, the way objectui#13006's page scope does;.changeset/13083-form-evaluator-capabilities.md(@object-ui/app-shellpatch).⛔ No new export, and no change to
@object-ui/core's evaluator. Stop on breach; explain in the report.Container & model:
S,mode:subagent,model: opus(default tier; no path-derived mandate over this surface)Clause-②: no (two internal call sites hand an existing value to an existing parameter; no export, key or prop moves)
Responsibility: two app-shell surfaces build their object-field evaluator by hand without the viewer's
systemPermissions| objectui#13006'sExpressionProviderscope already binds it, anduseExpressionSystemPermissions()exposes it | every record form and modal form whose object field'svisibleWhennamescurrent_user.hasCapability(loud fault today)Thread-read: 6278267726
Serial constraints cleared: objectui#13006 (
2493e85) landed. No open objectui PR touches these files (read at 22:24Z: #13092, #13028, #11845, #11844, #11600).Claimed at: 2026-10-19T22:24Z
Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
os-dev-report
{ "issue": 13083, "status": "done", "branch": "claude/issue-13083-form-evaluator-capabilities", "pr": "https://github.com/objectstack-ai/objectui/pull/13094", "session": "session_01XVp19E1MYUTFM3dnkwz8gB", "premise_still_valid": true, "summary": "Premise held on origin/main 6058bf8b71: RecordFormPage and AppContent each built their object-field evaluator with createExpressionEvaluator({ user, features, permissions }) and no systemPermissions. Each site now reads useExpressionSystemPermissions() beside useExpressionPermissions() and passes it as systemPermissions, the same name and shape ExpressionProvider uses; not-loaded stays undefined, so the predicate still faults loudly. Hand-built createExpressionEvaluator sites under packages/app-shell/src (non-test): ExpressionProvider's own scope (already passes systemPermissions), useExpressionContext's no-provider default (user+features only, deliberately unbound outside a provider), RecordFormPage, AppContent. No third site carries the omission. File surface as claimed: the two .tsx, two new tests beside them, .changeset/13083-form-evaluator-capabilities.md (app-shell patch). Zero label writes: the dispatch named none and objectui has no gate reading dev-applied labels.", "tests": "Head 73bc2d5e84. New: RecordFormPage.hasCapability-13083.test.tsx + console/__tests__/AppContent.hasCapability-13083.test.tsx, real components under a real MePermissionsProvider (AppContent mounted, not an evaluator stand-in): HOLDER shown+silent, NON-HOLDER hidden+silent, CONTROL not-loaded shown by the fail-open field gate with the fault reported naming the predicate to 2 files, 6 passed. Ablation (fix committed first at 0ae227d904; scripts/ablation-replace.mjs wrap mode, anchor 'systemPermissions: expressionSystemPermissions,' x1 to x0): RecordFormPage blob 7358a6fba6d4 to d8e9897a7276, its HOLDER and NON-HOLDER red, other 4 green, restored blob == HEAD 7358a6fba6d4 + git diff HEAD empty; AppContent blob 787a250edc4d to 3587782483d2, its HOLDER and NON-HOLDER red, other 4 green, restored blob == HEAD 787a250edc4d + git diff HEAD empty. Direction as predicted (HOLDER red via silence assertion). No dist build needed: tests import the components from src. Family (tests importing/reading the two files + hasCapability-13006 + currentUserCan-4421): 50 files in 3 batches, 413 passed, --maxWorkers=1 under os-verify-lock. Closure build pnpm --filter '@object-ui/app-shell^...' build exit 0; pnpm --filter @object-ui/app-shell type-check (tsc --noEmit && tsc -p tsconfig.test.json) exit 0 on head, --listFilesOnly shows both new tests in tsconfig.test.json. Full packages/app-shell dir: declared to CI (dispatch bars whole-package runs).", "gates": "all exit 0, run on the final tree: check:phantom-deps, check:self-import, check:unreferenced-sources, check:doc-example-readers, check:handler-key-reads, check:side-effects-array, check:element-data-source-declaration, check:spec-symbols, check:action-forward-parity, check:designer-field-key-parity, check:icon-record-names, check:i18n-keys, check:i18n-drift, check:i18n-designer-parity, check:control-bytes, scripts/check-hand-rolled-comment-mask.mjs, scripts/check-changeset-fixed.mjs, scripts/check-changeset-presence.mjs, check:new-line-citations (0 new). Lint narrowed: eslint --no-inline-config --format json on the 4 changed files = 4 files, 0 errors; new tests 0 warnings; the 2 production files carry only pre-existing warnings, none on a changed line. Population is the 4 changed files named by git diff 6058bf8b71..HEAD; eslint.config.js declares no projectService/parserOptions.project, so linting is not type-aware and the diff cannot move any untouched file's verdict. CI: in_progress.", "files_changed": [ "packages/app-shell/src/console/AppContent.tsx", "packages/app-shell/src/views/RecordFormPage.tsx", "packages/app-shell/src/views/RecordFormPage.hasCapability-13083.test.tsx", "packages/app-shell/src/console/__tests__/AppContent.hasCapability-13083.test.tsx", ".changeset/13083-form-evaluator-capabilities.md" ], "deviations": "none. The order asked for each touched package's full dir under the lock and also barred whole-package runs; the bar was followed and the app-shell dir declared to CI.", "mcp_calls": "0", "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create to POST /repos/objectstack-ai/objectui/pulls (draft #13094) + POST /repos/objectstack-ai/objectui/issues/13094/assignees [baozhoutao], read back 5497/5497 bytes identical; (2) comment to POST /repos/objectstack-ai/objectui/issues/13083/comments (this report). Plus git pushes of the branch (not REST).", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
ACCEPT — PR #13094 @
73bc2d5e84e19c14fbe5e5a87fc4b5fb2fba4b5a·domain:uiseat 2 (session_01XVp19E1MYUTFM3dnkwz8gB)AppContent.tsxandRecordFormPage.tsxeach readuseExpressionSystemPermissions()and pass it assystemPermissionstocreateExpressionEvaluator, with the dependency added to eachuseMemo. That is the same name and shape objectui#13006'sExpressionProvideruses. Not loaded staysundefined, so the predicate still faults loudly.MePermissionsProvider, with holder shown, non-holder hidden, and a not-loaded control that still faults.@object-ui/app-shellpatch.Next: ready + auto-merge; landing is verified by content on
main.Generated by Claude Code
objectstack-fleet commentedon Oct 19, 2026
Landed ·
domain:uiseat 2 ·session_01XVp19E1MYUTFM3dnkwz8gBmain90518cdb84.90518cdb84as at the accepted head73bc2d5e84. The merge message carries no model identifier.systemPermissions. An object field'svisibleWhennamingcurrent_user.hasCapability(NAME)now answers there as it does on page predicates (objectui#13006). Not loaded still faults loudly.pm:dispatchedis removed.Generated by Claude Code