Skip to content

fix(objectql): enforce per-option visibleWhen on checkboxes + string-match option values (objectui#2729) - #3350

Merged
os-zhuang merged 1 commit into
mainfrom
feat/2729-checkboxes-option-gating
Jul 20, 2026
Merged

os-zhuang merged 1 commit into
mainfrom
feat/2729-checkboxes-option-gating

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Addresses objectstack-ai/objectui#2729 (server-side enforcement of role-gated / dependent option values).

Context

Server-side per-option visibleWhen enforcement already exists (packages/objectql/src/validation/rule-validator.ts → evaluateOptionVisibility, wired into insert / single-update / bulk-update). Investigating objectui#2729 surfaced that it covered select / multiselect / radio but left two holes that let gated values through on write — the exact "client hides it, server must reject it" boundary the issue is about.

Fixes

  1. checkboxes was not enforced. CHOICE_FIELD_TYPES omitted checkboxes, so fieldHasOptionVisibility returned false for it and its options were never re-evaluated. Since objectui#2735 shipped client-side checkboxes cascading, a gated checkboxes option was hidden in the UI yet accepted from a crafted write. Added checkboxes to the enforced set — picked values are now checked element-wise against each option's visibleWhen (record + current_user), like multiselect. (checkboxes is already treated as a multi-value option field by the enum validator, so this closes an inconsistency between the two validators.)

  2. Numeric option values could slip the gate. Option matching used strict ===, but the enum-membership validator (record-validator.ts) compares by String(...). A numeric option value submitted as a string (a normal REST/JSON round-trip) passed the enum check but its visibleWhen gate found no matching option and fail-opened. Matching now coerces both sides with String(...), so the enum and visibility validators agree on which option a written value denotes.

Not changed / by design

  • select / multiselect / radio behavior is unchanged.
  • Fail-open on unbound current_user (system writes) or unevaluable predicates is preserved — a broken cascade predicate must never brick a write; authorization gating depends on the engine binding current_user, as before.
  • dependsOn remains a client form-gating hint only; server enforcement keys off each option's visibleWhen (a cascade parent is expressed inside the child's predicate, e.g. record.country == 'cn'), matching the existing design.

Tests

  • Extended rule-validator.option-visibility.test.ts: checkboxes element-wise gating (+ needsPriorRecord), and numeric-value coercion (both are real regression guards — they fail on the pre-fix code).
  • Verified green: objectql src/validation/ + engine.test.ts (206 passed) and plugin.integration.test.ts real-registry path (36 passed). tsc --noEmit clean; eslint 0 errors (one pre-existing unrelated no-new warning).

🤖 Generated with Claude Code

…ption values by string (objectui#2729)

Server-side per-option gating covered select/multiselect/radio but two holes
let gated values through on write:

- checkboxes was excluded from CHOICE_FIELD_TYPES, so a gated `checkboxes`
  option (client widget cascades like multiselect since objectui#2715) was
  hidden in the UI but accepted from a crafted write. Now enforced element-wise
  on insert/update/bulk-update like multiselect.
- Option matching used strict `===` while the enum validator compares by
  String(...); a numeric option value sent as a string passed the enum check
  but missed its visibleWhen gate (fail-open). Now coerces both sides.

select/multiselect/radio behavior unchanged; fail-open on unbound current_user /
unevaluable predicates preserved. Adds checkboxes + coercion cases to
rule-validator.option-visibility.test.ts.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 20, 2026 6:03am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/s labels Jul 20, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/objectql.

13 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/objectql)
  • content/docs/data-modeling/formulas.mdx (via packages/objectql)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/objectql)
  • content/docs/deployment/vercel.mdx (via @objectstack/objectql)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/objectql)
  • content/docs/kernel/services.mdx (via @objectstack/objectql)
  • content/docs/permissions/authentication.mdx (via @objectstack/objectql)
  • content/docs/plugins/index.mdx (via @objectstack/objectql)
  • content/docs/plugins/packages.mdx (via @objectstack/objectql)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/objectql)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/objectql)
  • content/docs/releases/implementation-status.mdx (via @objectstack/objectql)
  • content/docs/releases/v9.mdx (via @objectstack/objectql)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 674457a into main Jul 20, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the feat/2729-checkboxes-option-gating branch July 20, 2026 06:07
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Jul 20, 2026
…d + Console)

Continues the v16 page from the latest front/back-end code. Since the rc.0 cut,
9 backend changesets landed and the objectui pin advanced 94d4876 -> af1b0db
(objectui objectstack-ai#2706-objectstack-ai#2736). Sourced from each repo's own changesets.

- Retitles the now-stale 'pending the next console pin' subsection: those 4
  frontend items (objectui#2701/objectstack-ai#2706/objectstack-ai#2707/objectstack-ai#2708) are now bundled as the pin
  advanced; points to the new running section.
- Adds a 'Landed since 16.0.0-rc.0' section:
  - Breaking/behavior: aiStudio/aiSeat alias removal (objectstack-ai#3308); date-arithmetic
    now a build-time error (objectstack-ai#3306); checkboxes per-option visibleWhen + string
    option matching (objectstack-ai#3350).
  - New backend: formula null-guard/floor/ceil (objectstack-ai#3306); engine-owned managedBy
    bucket (ADR-0103 addendum, objectstack-ai#3343); approvals viewer gating (objectstack-ai#3344) +
    decision attachments (objectstack-ai#3332); discovery transactionalBatch bit (objectstack-ai#3298);
    action resultDialog i18n (objectstack-ai#3347); collab-notification/storage localization
    + wired notifications REST routes (objectstack-ai#3354).
  - Console (now bundled): option-widget visibleWhen parity, approvals-inbox
    server-viewer gating + composer retirement, related-list pagination,
    inline-analytics renderer retirement, authenticated api-fetch threading,
    result-dialog i18n, engine-owned bucket UI, write-failure surfacing.
- Adds aiStudio/aiSeat and date-arithmetic to the upgrade checklist; updates
  the Console-section intro for the advanced pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AHVoqyH9VAjmbyMN1Ri2jf
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Aug 17, 2026
…ectstack-ai#8886) (objectstack-ai#8912)

The v16 page and its index entry still described the train as published as
`16.0.0-rc.0`. Tags say otherwise: `@objectstack/spec@16.0.0-rc.0` (2026-07-19),
`-rc.1` (2026-07-20), `16.0.0` (2026-07-21), `16.1.0` (2026-07-22). The series
went GA, took a minor, and closed when 17.0.0 shipped on 2026-08-14.

Four stale surfaces on the page, not one:

1. The release-status blockquote — rewritten as shipped, following the shape
   objectstack-ai#8882 set for v17. The "section headings say 16.0.0 for brevity" sentence is
   dropped (it explained a pre-mode convention that no longer exists); the
   trailing 15.1.1 cross-reference is kept verbatim — it is still true.
2. "Console vs. pin" said the pin "has since advanced to `af1b0db` on `main`".
   That advance released: changeset 1965549 bundles `af1b0db96e44` in
   `@objectstack/console` 16.0.0-rc.1.
3. "Console changes after the `rc.0` pin" carried the same `on main` framing.
4. The `Landed since 16.0.0-rc.0` window was left **open** ("roll into the next
   16.0 RC"). It is closed against what actually released it, in the shape the
   v17 windows use. Every entry in it maps to a changeset consumed at the
   `16.0.0-rc.1` cut — objectstack-ai#3308 (06ff734), objectstack-ai#3347 (6289ec3), objectstack-ai#3298 (bfa3c3f),
   objectstack-ai#3306 (7125007), objectstack-ai#3343 (62a2117), objectstack-ai#3350 (674457a), objectstack-ai#3332 (e412fb6),
   objectstack-ai#3344 (8efa395), objectstack-ai#3354 (ee0a499) and the console pin (1965549) — and the
   16.0.0 GA changelog sections re-list rc.0 + rc.1, the signature of
   `changeset pre exit`, so the window shipped in 16.0.0.

The 16.1.0 minor is named as the line's final release but deliberately not
documented: its content is out of this PR's scope.


Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm

Co-authored-by: Claude <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 1de36d9a Deployed Jul 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant