B3: cascading-option guardrail, role-gated demo, ADR-0058 + browser e2e (#1583)#2547
Merged
Merged
Conversation
…wser e2e (#1583) Complete the objectui side of B3 (dynamic field options / cascading selects): a build-time guardrail for per-option `visibleWhen` predicates, a role-gated showcase example, ADR-0058, and a real-browser cascade e2e. The client feature itself shipped in #2284/#2215 (v12.0.0); this fills the remaining objectui checklist. - @object-ui/core: `lintOptionPredicates()` statically validates option `visibleWhen` predicates — CEL syntax (via @objectstack/formula `validateExpression`), unknown `record.<field>` references, and a literal compared against an enum sibling outside its value domain (`record.country == 'chna'`, the #2284 AI-typo case). Conservative: only flags what it can statically prove; role/context predicates (`current_user.*`) and open-domain fields are left alone (no false positives). - examples/schema-catalog: role-gated select demo (`current_user.roles`), wired live into the Select field docs page; a new catalog test runs the guardrail over every shipped example. - e2e/cascading-options.spec.ts: drives the shipped country -> province example on the docs site (no backend), asserting the offered set re-filters live and a stale child value clears. Auto-skips when the docs site isn't served, like docs-smoke. - docs/adr/0058: the B3 decision record (per-option `visibleWhen` + `dependsOn` over `optionsWhen`/`validFor`; dual-side contract; server-enforcement contract). Server-side option-value enforcement and the live-backend e2e remain framework-side (tracked in #1583). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UFBvVjdHzB29XabjYxe1bN
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Completes the objectui side of B3 — dynamic field options / cascading selects (#1583). The client feature itself (per-option
visibleWhen+dependsOn) shipped earlier in #2284 / #2215 (v12.0.0); this PR fills the remaining objectui checklist from the rewritten #1583: a build-time guardrail, a role-gated demo, the ADR, and a real-browser e2e.Changes
@object-ui/core—lintOptionPredicates()(packages/core/src/evaluator/optionLint.ts): a static, conservative validator for per-optionvisibleWhenCEL predicates. An option predicate fails closed (a wrong one makes its option silently never appear), which runtime fail-open can't surface. Three checks:syntax— invalid CEL, delegated to@objectstack/formula'svalidateExpression(no schema hint, so a legitimatecurrent_user.rolesreference is never flagged);unknown-field— arecord.<name>reference to a field the form never declares;option-literal-not-in-domain— a literal compared against an enum sibling that is outside its declared option values, e.g.record.country == 'chna'whencountryiscn/us(the AI-authoring typo 表单支持级联/依赖选项:新增 SelectOption.visibleWhen 通用谓词 #2284 called out).It only flags what it can statically prove —
current_user.*, open-domain fields, and unrecognized shapes are left alone, so there are no false positives.Catalog guard (
examples/schema-catalog/test/option-predicates.test.tsx): runs the guardrail over every shipped example in CI (pnpm test), and asserts it's non-vacuous against the cascade example.Role-gated demo (
examples/schema-catalog/.../role-gated-options.json): a select with acurrent_user.roles-gated option, wired live into the Select field docs page (content/docs/fields/select.mdx).docs/adr/0058-cascading-select-options.md: the B3 decision record — per-optionvisibleWhen+dependsOn(overoptionsWhen/validFor), the dual-side contract, the client implementation, and the server-enforcement contract.e2e/cascading-options.spec.ts: drives the shippedcountry → provinceexample on the docs site (no backend) in a real browser, asserting the offered set re-filters live (China → Zhejiang/Guangdong; US → California/Texas) and the stale child value clears. Auto-skips when the docs site isn't served, mirroringdocs-smoke.spec.ts.Verification
optionLintunit tests (12) + catalog guardrail over 417 examples + full core evaluator suite (244) — all green.tsc --buildclean on the changed packages.Out of scope (framework-side, still tracked in #1583)
visibleWhenis FALSE, in the@objectstack/objectqlrule path (mirroringstripReadonlyWhenFields).These live in
objectstack-ai/frameworkand need that repo added to the session; happy to follow up there.Closes part of #1583 (objectui side).
🤖 Generated with Claude Code
https://claude.ai/code/session_01UFBvVjdHzB29XabjYxe1bN
Generated by Claude Code