Skip to content

fix(ai-context): load custom properties into rule builder filter - #31635

Merged
anuj-kumary merged 15 commits into
mainfrom
fix/persona-ai-context-custom-properties-filter
Aug 18, 2026
Merged

fix(ai-context): load custom properties into rule builder filter#31635
anuj-kumary merged 15 commits into
mainfrom
fix/persona-ai-context-custom-properties-filter

Conversation

@anuj-kumary

@anuj-kumary anuj-kumary commented Aug 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Bug fix: "Custom Properties" in the AI Context Rule Builder's filter showed an empty "Select field" dropdown even when custom properties exist for the selected entity type
  • Root cause: RuleQueryBuilderField passed the raw base config (which has extension.subfields = {}) to QueryBuilderWidgetV1 without ever fetching custom properties. AdvanceSearchProvider does this fetch but its logic was never wired into the rule builder
  • Fix: Added a useEffect in RuleQueryBuilderField that calls getAllCustomProperties() on mount (re-runs when entityType changes), builds enriched fields with extension.subfields populated, and passes them to QueryBuilderWidgetV1 via the fields prop
  • Playwright regression test: Added "Service Is [value]" test (async-dropdown path) to PersonaAIContextRules.spec.ts — a gap the existing "Description Contains" plain-text test cannot cover. Uses a DatabaseServiceClass fixture for a deterministic service to select

Test plan

  • Open Settings → Personas → [any persona] → AI Context → Add Rule
  • Select "Table" as entity type, add a condition, choose "Custom Properties" as the field
  • Verify the "Select field" dropdown now shows the Table's custom properties (e.g. testc of type Enum)
  • Select a custom property and value, click Save Rule — should save successfully with no filter error
  • Playwright: PersonaAIContextRules.spec.ts — "fully-completed Service Is condition allows save"

🤖 Generated with Claude Code

Greptile Summary

The PR loads entity custom properties into the AI Context rule builder and expands its Playwright regression coverage.

  • Fetches and transforms custom-property definitions into query-builder extension subfields.
  • Rebuilds the available fields for the selected entity type.
  • Adds custom-property and asynchronous-dropdown regression scenarios alongside broader AI Context coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/components/Settings/Persona/PersonaAIContext/ContextRuleEditor/RuleQueryBuilderField.component.tsx Enriches the query-builder configuration with custom-property subfields fetched through the existing metadata-type REST client.
openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/PersonaAIContext.spec.ts Adds regression coverage for custom-property loading, asynchronous values, serialization, cache states, and related AI Context interactions.

Reviews (13): Last reviewed commit: "Merge branch 'main' into fix/persona-ai-..." | Re-trigger Greptile

Context used:

…add Service Is regression test

The "Custom Properties" field in the AI Context Rule Builder showed an
empty "Select field" dropdown because RuleQueryBuilderField never fetched
custom properties — only AdvanceSearchProvider did. Fix: fetch
getAllCustomProperties() on mount (keyed to entityType), build enriched
fields with extension.subfields populated, and pass them to
QueryBuilderWidgetV1 via the fields prop.

Also adds a Playwright regression test for the fully-completed "Service Is"
condition (async-dropdown path) that the existing "Description Contains"
test cannot cover, and wires a DatabaseServiceClass fixture for it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

❌ PR checklist incomplete

This PR cannot be merged until the following are addressed on its linked issue:

  • No GitHub issue is linked. Link an issue in the Development section of the PR (or add Fixes #12345 to the description). For a same-org cross-repo issue, add Fixes open-metadata/<repo>#123 to the description.

The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically.

Maintainers can bypass this check by adding the skip-pr-checks label.

@github-actions github-actions Bot added the UI UI specific issues label Aug 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Hi there 👋 Thanks for your contribution!

The OpenMetadata team will review the PR shortly! Once it has been labeled as safe to test, the CI workflows
will start executing and we'll be able to make sure everything is working as expected.

Let us know if you need any help!

@anuj-kumary anuj-kumary added safe to test Add this label to run secure Github workflows on PRs skip-pr-checks Bypass PR metadata validation check labels Aug 17, 2026
anuj-kumary and others added 4 commits August 17, 2026 17:51
…o PersonaAIContext.spec.ts

The two new regression tests belong in the existing PersonaAIContext.spec.ts
alongside the other rule-builder tests rather than as additions to
PersonaAIContextRules.spec.ts. Removes the DatabaseServiceClass fixture and
Service Is test from PersonaAIContextRules.spec.ts (restoring it to the
merged state) and adds both tests to PersonaAIContext.spec.ts where the
dbService fixture is shared with the full suite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Covers 9 previously untested scenarios in PersonaAIContext.spec.ts:
- Sections checkbox toggle → payload omits unchecked section
- Rule description persisted in POST payload
- View in Explore href updates when entity type changes
- Preview modal closes via the Close button
- STALE cache state badge on settings card
- FAILED cache state badge + lastError text
- Edit drawer Escape discards unsaved changes
- Rule card displays matched asset count from server
- Compound OR conditions serialized into queryFilter payload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract PROBE_RULE const — eliminates inline rule object duplication
  across cache-state tests, edit-discard test, and matched-count test
- Add overrideAiContextGet helper — replaces 40-line copy-paste in the
  stale and failed cache-state tests with a 3-line call each
- Scope all query-builder locators to getByRole('dialog') in the
  compound OR test so they never match elements outside the drawer
- Add explicit wait for second condition row (toHaveCount(2)) before
  interacting with it in the compound OR test
- Add post-save card assertion to sections, description, and compound OR
  tests so each test has a complete pass/fail postcondition
- Fix View in Explore assertion: /\/explore\// → /\/explore\/glossaries/
  (SearchClassBase maps GLOSSARY_TERM → ExplorePageTabs.GLOSSARY = 'glossaries')
- Improve matchedCount assertion: '57' → /57.*matched/ to avoid
  incidental matches on other '57' text on the page
- Use test.step() in the compound OR test for clearer Playwright reports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
RuleQueryBuilderField.component.tsx:
- Fetch getAllCustomProperties() once on mount instead of on every
  entityType change. The API returns all entity types' properties
  regardless of selection; only processEntityTypeFields is entity-type-
  specific. Split into two effects: the first (dep: []) fetches and
  caches the map in state; the second (dep: [entityType, customProps])
  processes it without a network request on each type switch.
- Fix no-internal-barrel-imports lint warning: replace the barrel import
  of DrawerPopupContainerProvider with the direct component file path.
- Remove the now-unnecessary useRef/cancelRef because the fetch runs
  once and there is no longer a stale-update race to guard against.

PersonaAIContext.spec.ts:
- Guard the Service Is value dropdown against Elasticsearch indexing
  latency: poll the search API (expect.poll, 30 s timeout) before
  calling selectOption so the test does not time out with "No data"
  if the newly created dbService has not yet been indexed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 66%
66.85% (79932/119552) 51.26% (48774/95149) 52.25% (14612/27964)

@github-actions

github-actions Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

✅ Playwright Results — workflow succeeded

Validated commit 8538a15b3a3e2cb16ca49cc0d8682bec5d508ff4 in Playwright run 32102405814, attempt 1.

✅ 120 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 0 skipped · 🧰 0 lifecycle flaky

Performance

Blocking targets: ✅ met · Optimization targets: 🟡 in progress

Shard-job maxima below are not the full workflow wall time; the linked run includes build, fixture, planning, and reporting.

🕒 Full workflow signal wall (to summary) 53m 40s

⏱️ Max setup 1m 52s · max shard execution 9m 27s · max shard-job elapsed before upload 14m 14s · reporting 2s

🌐 147.86 requests/attempt · 1.57 app boots/UI scenario · 0.00% common-shard skew

Optimization targets still in progress:

  • Application boot ratio was 1.57 per UI scenario (192 boots / 122 scenarios; convergence target: at most 1).
Shard Passed Failed Flaky Skipped Lifecycle failed Lifecycle flaky
✅ Shard chromium-01 110 0 0 0 0 0
✅ Shard global-state-01 10 0 0 0 0 0

📦 Download artifacts

How to debug locally
# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip    # view trace

…ependency

The value dropdown for "Service Is" calls /api/v1/search/aggregate with
field=service — it aggregates over TABLE documents, not service entities.
Because dbService has no tables, its name never appears in the
aggregation no matter how long we poll, making the test time out in CI.

Replace the ES poll with a direct route mock that returns the service
name immediately via the sterms#service bucket, keeping the test fast
and deterministic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…keyword

EntityFields.SERVICE = 'service.displayName.keyword', so the mock
aggregation bucket must use 'sterms#service.displayName.keyword' as the
key, not 'sterms#service'. The mismatch caused parseBucketsData to read
undefined.buckets, returning no options and leaving the dropdown empty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…yName.keyword

The route condition compared field === 'service' but the actual query
param sent by getAggregateFieldOptions is field=service.displayName.keyword
(EntityFields.SERVICE). The mismatch caused route.fallback() to run,
hitting the real server which returned no buckets (service has no
indexed tables), so the dropdown showed "Not found".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
anuj-kumary and others added 2 commits August 18, 2026 00:46
…ng conjunction

Clicking the RAQB 'Or' conjunction button before the second rule exists
causes it to prepend a nested OR group rather than just toggling the
conjunction. This means .last() targets the original rule_alpha (not a
new slot) and overwrites 'alpha' with 'beta', leaving only 'beta' in
the serialized query.

Fix: add both conditions with the custom add-context-condition button
(addRule([]) to the root group) first, then switch the conjunction to
OR — which only changes the group operator without any structural
change, keeping both alpha and beta in the payload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…es before conjunction change

- Move toHaveCount(2) assertion to step 1 (after the first addRule — 2 delete
  buttons: owners inner rule + new rule)
- Change step 2 toHaveCount assertion to 3 (owners inner + alpha rule + beta rule)
- Press Tab after fill('alpha') and fill('beta') to blur and commit values to
  the RAQB immutable tree before the conjunction change fires

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@anuj-kumary
anuj-kumary enabled auto-merge August 18, 2026 05:29
@sonarqubecloud

Copy link
Copy Markdown

@anuj-kumary
anuj-kumary added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 84197a5 Aug 18, 2026
80 of 82 checks passed
@anuj-kumary
anuj-kumary deleted the fix/persona-ai-context-custom-properties-filter branch August 18, 2026 12:21
@gitar-bot

gitar-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 resolved / 2 findings

Loads custom properties into the AI Context rule builder and expands Playwright regression test coverage. No issues found.

✅ 2 resolved
Performance: Custom properties re-fetched on every entityType change

📄 openmetadata-ui/src/main/resources/ui/src/components/Settings/Persona/PersonaAIContext/ContextRuleEditor/RuleQueryBuilderField.component.tsx:60-74
The useEffect re-runs getAllCustomProperties() each time entityType changes (dependency array [entityType]). getAllCustomProperties() returns custom properties for all entity types and processEntityTypeFields merely filters the already-fetched result by entityType, so switching entity types issues a redundant network request that returns identical data. Consider fetching the raw custom-property map once (e.g., store it in state/ref) and only re-running the client-side processEntityTypeFields/config rebuild when entityType changes.

Quality: Service Is test may be flaky due to ES indexing latency

📄 openmetadata-ui/src/main/resources/ui/playwright/e2e/Features/PersonaAIContextRules.spec.ts:367-371
The new 'Service Is' test creates dbService via the API in beforeAll and then relies on it appearing in the async value dropdown, which is backed by the search index. Newly created entities may not be immediately searchable due to Elasticsearch refresh latency, which can make the test intermittently fail when the option isn't yet indexed. Consider waiting for the service to be searchable (poll the search API) before opening the dropdown, or use selectOption with an explicit retry/wait on the option becoming visible.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Powered by Gitar — free for open source

anuj-kumary added a commit that referenced this pull request Aug 18, 2026
)

* fix(ai-context): load custom properties into rule builder filter and add Service Is regression test

The "Custom Properties" field in the AI Context Rule Builder showed an
empty "Select field" dropdown because RuleQueryBuilderField never fetched
custom properties — only AdvanceSearchProvider did. Fix: fetch
getAllCustomProperties() on mount (keyed to entityType), build enriched
fields with extension.subfields populated, and pass them to
QueryBuilderWidgetV1 via the fields prop.

Also adds a Playwright regression test for the fully-completed "Service Is"
condition (async-dropdown path) that the existing "Description Contains"
test cannot cover, and wires a DatabaseServiceClass fixture for it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(playwright): move Custom Properties and Service Is tests into PersonaAIContext.spec.ts

The two new regression tests belong in the existing PersonaAIContext.spec.ts
alongside the other rule-builder tests rather than as additions to
PersonaAIContextRules.spec.ts. Removes the DatabaseServiceClass fixture and
Service Is test from PersonaAIContextRules.spec.ts (restoring it to the
merged state) and adds both tests to PersonaAIContext.spec.ts where the
dbService fixture is shared with the full suite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* test(playwright): add comprehensive coverage for Persona AI Context

Covers 9 previously untested scenarios in PersonaAIContext.spec.ts:
- Sections checkbox toggle → payload omits unchecked section
- Rule description persisted in POST payload
- View in Explore href updates when entity type changes
- Preview modal closes via the Close button
- STALE cache state badge on settings card
- FAILED cache state badge + lastError text
- Edit drawer Escape discards unsaved changes
- Rule card displays matched asset count from server
- Compound OR conditions serialized into queryFilter payload

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor(playwright): improve Persona AI Context test quality

- Extract PROBE_RULE const — eliminates inline rule object duplication
  across cache-state tests, edit-discard test, and matched-count test
- Add overrideAiContextGet helper — replaces 40-line copy-paste in the
  stale and failed cache-state tests with a 3-line call each
- Scope all query-builder locators to getByRole('dialog') in the
  compound OR test so they never match elements outside the drawer
- Add explicit wait for second condition row (toHaveCount(2)) before
  interacting with it in the compound OR test
- Add post-save card assertion to sections, description, and compound OR
  tests so each test has a complete pass/fail postcondition
- Fix View in Explore assertion: /\/explore\// → /\/explore\/glossaries/
  (SearchClassBase maps GLOSSARY_TERM → ExplorePageTabs.GLOSSARY = 'glossaries')
- Improve matchedCount assertion: '57' → /57.*matched/ to avoid
  incidental matches on other '57' text on the page
- Use test.step() in the compound OR test for clearer Playwright reports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(ai-context): address PR review findings

RuleQueryBuilderField.component.tsx:
- Fetch getAllCustomProperties() once on mount instead of on every
  entityType change. The API returns all entity types' properties
  regardless of selection; only processEntityTypeFields is entity-type-
  specific. Split into two effects: the first (dep: []) fetches and
  caches the map in state; the second (dep: [entityType, customProps])
  processes it without a network request on each type switch.
- Fix no-internal-barrel-imports lint warning: replace the barrel import
  of DrawerPopupContainerProvider with the direct component file path.
- Remove the now-unnecessary useRef/cancelRef because the fetch runs
  once and there is no longer a stale-update race to guard against.

PersonaAIContext.spec.ts:
- Guard the Service Is value dropdown against Elasticsearch indexing
  latency: poll the search API (expect.poll, 30 s timeout) before
  calling selectOption so the test does not time out with "No data"
  if the newly created dbService has not yet been indexed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(playwright): mock aggregate API in Service Is test to remove ES dependency

The value dropdown for "Service Is" calls /api/v1/search/aggregate with
field=service — it aggregates over TABLE documents, not service entities.
Because dbService has no tables, its name never appears in the
aggregation no matter how long we poll, making the test time out in CI.

Replace the ES poll with a direct route mock that returns the service
name immediately via the sterms#service bucket, keeping the test fast
and deterministic.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(playwright): correct aggregate key to sterms#service.displayName.keyword

EntityFields.SERVICE = 'service.displayName.keyword', so the mock
aggregation bucket must use 'sterms#service.displayName.keyword' as the
key, not 'sterms#service'. The mismatch caused parseBucketsData to read
undefined.buckets, returning no options and leaving the dropdown empty.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(playwright): fix aggregate field param check — use service.displayName.keyword

The route condition compared field === 'service' but the actual query
param sent by getAggregateFieldOptions is field=service.displayName.keyword
(EntityFields.SERVICE). The mismatch caused route.fallback() to run,
hitting the real server which returned no buckets (service has no
indexed tables), so the dropdown showed "Not found".

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(playwright): fix compound OR test — add both rules before switching conjunction

Clicking the RAQB 'Or' conjunction button before the second rule exists
causes it to prepend a nested OR group rather than just toggling the
conjunction. This means .last() targets the original rule_alpha (not a
new slot) and overwrites 'alpha' with 'beta', leaving only 'beta' in
the serialized query.

Fix: add both conditions with the custom add-context-condition button
(addRule([]) to the root group) first, then switch the conjunction to
OR — which only changes the group operator without any structural
change, keeping both alpha and beta in the payload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix lint checks

* fix(playwright): fix compound OR test count assertion and commit values before conjunction change

- Move toHaveCount(2) assertion to step 1 (after the first addRule — 2 delete
  buttons: owners inner rule + new rule)
- Change step 2 toHaveCount assertion to 3 (owners inner + alpha rule + beta rule)
- Press Tab after fill('alpha') and fill('beta') to blur and commit values to
  the RAQB immutable tree before the conjunction change fires

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix lint checks

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 84197a5)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

safe to test Add this label to run secure Github workflows on PRs skip-pr-checks Bypass PR metadata validation check UI UI specific issues

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants