Proposal: Operator Taxonomy by Attribute Type in ABAC Simple Mode
BLUF
Rename in to is any of for select fields, remove in from text fields entirely, and filter string operators (starts with, ends with, contains) to text fields only. This eliminates the in/contains semantic ambiguity, aligns select and multiselect naming patterns (is any of / has any of), and avoids the unsolved UX of multi-value free-text input. Every major platform (Jira, Salesforce, Airtable, Notion) filters operators by field type and uses distinct labels for list membership vs. substring matching.
The Problems This Solves
1. in vs contains — same word, different operations
in = exact match against a list of values ("dept is exactly Eng or Ops"). contains = substring match ("dept contains 'Eng'"). But in plain English both imply "membership." An admin who picks contains thinking "is contained in this set" gets a substring match instead — silently over-permissioning the policy.
2. in (select) vs has any of (multiselect) — same operation, different names
Both mean "match any of these values." But the select field uses in while multiselect uses has any of. An admin who learns one pattern cannot find the equivalent on the other field type. Renaming in → is any of creates a parallel: is any of (select, single-value field) / has any of (multiselect, multi-value field).
3. in on text fields — no viable value input UX
For select fields, in shows a multi-chip dropdown because options are predefined. For text fields, the admin would need to type exact free-form strings into a chip input with no autocomplete — a misconfiguration magnet (typos, casing mismatches silently create non-matching rules). Half the industry (Airtable, Notion, Jira basic mode) omits multi-value exact match from text fields entirely for this reason.
Proposed Operator Matrix
Operator | Select | Text | Multiselect | CEL Output |
|---|---|---|---|---|
| Yes | Yes | — |
|
| Yes | Yes | — |
|
| Yes | No | — |
|
| No | Yes | — |
|
| No | Yes | — |
|
| No | Yes | — |
|
| — | — | Yes |
|
| — | — | Yes |
|
Why this specific set
Select fields get: is, is not, is any of
Values are predefined and finite — only exact-match operators apply
is any ofreplacesinwith a plain-English label that parallels multiselect'shas any ofString operators (
starts with,ends with,contains) are a category error on predefined values — they create policy drift risk when new options are added
Text fields get: is, is not, starts with, ends with, contains
Unbounded values need pattern matching —
starts with "ENG-"captures department naming conventionsis any ofis deliberately excluded: free-form multi-value exact match has no viable simple-mode UX (no autocomplete, typo-prone). Admins who need "dept is exactly Eng or Ops" can use twoisrows with global OR, or use the CEL editorcontainsis unambiguous here — it can only mean substring match on a text field. Thein/containsconfusion disappears becauseinno longer exists on text fields
Multiselect fields get: has any of, has all of (unchanged from previous proposal)
The naming pattern
Field Type | "Match one value" | "Match any of multiple values" |
|---|---|---|
Select |
|
|
Text |
| (use CEL or multiple rows) |
Multiselect | — |
|
The is / is any of / has any of progression is learnable: "is" for scalar exact match, "is any of" for scalar-against-list, "has any of" for set-against-set.
in vs contains — Detailed Disambiguation
These are technically different operations but the naming overlap is the root cause of confusion:
Operation | Old Name | New Name | What It Does | Example |
|---|---|---|---|---|
List membership (exact match against multiple values) |
|
| User's single value is one of these predefined options | Clearance |
Substring containment |
|
| User's text value contains this substring | Department |
By restricting each operator to its appropriate field type, the ambiguity disappears entirely. is any of only appears with a dropdown value picker (predefined options). contains only appears with a text input (free-form string). The value input itself signals the operation.
Competitive Validation
Platform | Select operators | Text operators | List-match label | Substring label |
|---|---|---|---|---|
Airtable | is, is not, is any of | is, is not, contains | is any of | contains |
Notion | is, is not | is, is not, contains, starts with, ends with | (not offered for text) | contains |
Jira | is, is not, IN | ~, = (JQL only) | IN | ~ (contains) |
Salesforce | equals, not equal, IN | equals, contains, starts with | equals / IN | contains |
Braze | equals, equals any of | equals, equals any of, contains | equals any of | contains |
Segment | is, is not | is, is not, contains, starts with, ends with | (not offered for text) | contains |
Key finding: No platform uses "contains" to mean list membership. "Contains" universally means substring. The platforms that serve non-technical users (Airtable, Notion) also restrict multi-value matching to select/enum fields — exactly our approach.
What This Looks Like
Select attribute (e.g., Clearance)
┌──────────────┐ ┌────────────┐ ┌────────────────────────────┐
│ Clearance ▼ │ │ is any of▼ │ │ Secret ✕ Top Secret ✕ │
└──────────────┘ └────────────┘ └────────────────────────────┘
Operator dropdown: Value input:
┌────────────┐ ┌─────────────────┐
│ is │ │ ☑ Secret │ ← predefined dropdown
│ is not │ │ ☑ Top Secret │
│ is any of │ │ ☐ Confidential │
└────────────┘ └─────────────────┘
Text attribute (e.g., Department)
┌──────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Department ▼ │ │ starts with▼ │ │ ENG- │
└──────────────┘ └──────────────┘ └──────────────────┘
Operator dropdown:
┌──────────────┐
│ is │
│ is not │
│ starts with │
│ ends with │
│ contains │
└──────────────┘
Multiselect attribute (e.g., Programs)
┌──────────────┐ ┌────────────┐ ┌──────────────────────────┐
│ Programs ▼ │ │ has any of▼│ │ Dragon ✕ Phoenix ✕ │
└──────────────┘ └────────────┘ └──────────────────────────┘
Operator dropdown:
┌────────────┐
│ has any of │
│ has all of │
└────────────┘
Cheatsheet Update
Group the syntax cheatsheet by attribute type:
Select attributes
Operator | Meaning | CEL Example |
|---|---|---|
| Exact match |
|
| Does not match |
|
| Matches any of the selected values |
|
Text attributes
Operator | Meaning | CEL Example |
|---|---|---|
| Exact match |
|
| Does not match |
|
| Begins with prefix |
|
| Ends with suffix |
|
| Contains substring |
|
Multiselect attributes
Operator | Meaning | CEL Example |
|---|---|---|
| User has at least one of these values |
|
| User has all of these values |
|
Implementation
Lightweight frontend change — same pattern as PR #35896's multiselect operator filtering:
Rename
in→is any ofin operator constants (display label only; internal enum unchanged)Filter operators by
attributeType: select →is,is not,is any of; text →is,is not,starts with,ends with,contains; multiselect →has any of,has all ofDefault operator per type: Select →
is, Text →is, Multiselect →has any ofReset operator on attribute type change — switching from text (
containsselected) to select resets toisValue input adapts: select operators use dropdown picker; text operators use free-form text input
No backend changes. No new UI components. No CEL generation changes.
Risk Register
Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
Admin needs multi-value exact match on text and can't express in simple mode | Low | Medium | Use two |
Renaming | Low | High | Verify operator labels are display-only. If stored, implement mapping migration. |
| Low | Low | Monitor usage. Can be removed in future release without breaking policies. |