Skip to content

fix(ui): correct is_not_set semantics for Owner/Domain/DataProduct co…#30439

Open
shrabantipaul-collate wants to merge 14 commits into
mainfrom
fix/data-contract-is-not-set-group-fields
Open

fix(ui): correct is_not_set semantics for Owner/Domain/DataProduct co…#30439
shrabantipaul-collate wants to merge 14 commits into
mainfrom
fix/data-contract-is-not-set-group-fields

Conversation

@shrabantipaul-collate

@shrabantipaul-collate shrabantipaul-collate commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

…ntract rules

The "Is Not Set" operator on group/some fields (Owners, Domain, DataProduct) emitted {"some": [var, {"==": [field, null]}]}, which JsonLogic evaluates as vacuously false on an empty array — so the rule always failed even when the entity genuinely had no owner/domain/data product. Extend the existing negation-lift transform (already used for array_not_contains/NOT_IN) to also rewrite this shape to {"!": {"some": [var, {"!=": [field, null]}]}}, and unskip the three affected Playwright tests.

Describe your changes:

Fixes #

I worked on ... because ...

Type of change:

  • Bug fix
  • Improvement
  • New feature
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation

High-level design:

N/A — small change.

Tests:

Use cases covered

Unit tests

Backend integration tests

Ingestion integration tests

Playwright (UI) tests

Manual testing performed

UI screen recording / screenshots:

Not applicable.

Checklist:

  • I have read the CONTRIBUTING document.
  • My PR title is Fixes <issue-number>: <short explanation>
  • My PR is linked to a GitHub issue via Fixes #<issue-number> above.
  • I have commented on my code, particularly in hard-to-understand areas.
  • For JSON Schema changes: I updated the migration scripts or explained why it is not needed.
  • For UI changes: I attached a screen recording and/or screenshots above.
  • I have added tests (unit / integration / Playwright as applicable) and listed them above.

Greptile Summary

Corrects generated Is Not Set JsonLogic for grouped fields.

  • Rewrites grouped some/==null expressions as the negation of some/!=null.
  • Adds focused unit coverage for the transformation.
  • Re-enables Owner, Domain, and DataProduct Playwright scenarios.

Confidence Score: 3/5

The PR is not safe to merge until direct validation of existing legacy Is Not Set rules receives the corrected semantics.

The correction is limited to interactive query-builder changes, while Run Now evaluates persisted legacy rules verbatim and therefore retains the original incorrect empty-array result.

openmetadata-ui/src/main/resources/ui/src/utils/JSONLogicSearchClassBase.ts and the Data Contract validation path

Important Files Changed

Filename Overview
openmetadata-ui/src/main/resources/ui/src/utils/JSONLogicSearchClassBase.ts Adds the grouped Is Not Set rewrite, but the edit-time transformation still does not migrate legacy persisted rules used by direct validation.
openmetadata-ui/src/main/resources/ui/src/utils/JSONLogicSearchClassBase.test.ts Adds unit coverage for direct and conjunction-wrapped grouped null expressions.
openmetadata-ui/src/main/resources/ui/playwright/e2e/Pages/DataContractsSemanticRules.spec.ts Re-enables end-to-end Is Not Set coverage for newly created Owner, Domain, and DataProduct rules.

Reviews (9): Last reviewed commit: "Merge branch 'main' into fix/data-contra..." | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

…ntract rules

The "Is Not Set" operator on group/some fields (Owners, Domain, DataProduct)
emitted `{"some": [var, {"==": [field, null]}]}`, which JsonLogic evaluates
as vacuously false on an empty array — so the rule always failed even when
the entity genuinely had no owner/domain/data product. Extend the existing
negation-lift transform (already used for array_not_contains/NOT_IN) to also
rewrite this shape to `{"!": {"some": [var, {"!=": [field, null]}]}}`, and
unskip the three affected Playwright tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@shrabantipaul-collate
shrabantipaul-collate requested a review from a team as a code owner July 24, 2026 07:14
@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

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!

@github-actions

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

✅ Playwright Results — workflow succeeded

Validated commit faef85187d461efd4ee1d7d874d149efb9172248 in Playwright run 30096011891, attempt 1.

✅ 578 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 5 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) 50m 46s

⏱️ Max setup 3m 0s · max shard execution 16m 56s · max shard-job elapsed before upload 20m 7s · reporting 4s

🌐 206.47 requests/attempt · 2.94 app boots/UI scenario · 5.31% common-shard skew

Optimization targets still in progress:

  • Browser traffic was 206.47 requests per attempt (convergence target: fewer than 200).
  • Application boot ratio was 2.94 per UI scenario (1762 boots / 599 scenarios; convergence target: at most 1).
Shard Passed Failed Flaky Skipped Lifecycle failed Lifecycle flaky
✅ Shard chromium-01 113 0 0 0 0 0
✅ Shard chromium-02 103 0 0 0 0 0
✅ Shard chromium-03 109 0 0 0 0 0
✅ Shard chromium-04 115 0 0 3 0 0
✅ Shard data-asset-rules-01 61 0 0 0 0 0
✅ Shard domain-isolation-01 14 0 0 0 0 0
✅ Shard global-state-01 23 0 0 0 0 0
✅ Shard ingestion-01 1 0 0 0 0 0
✅ Shard reindex-01 2 0 0 0 0 0
✅ Shard search-01 10 0 0 0 0 0
✅ Shard search-rbac-01 27 0 0 2 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

@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!

@shrabantipaul-collate shrabantipaul-collate added the safe to test Add this label to run secure Github workflows on PRs label Jul 24, 2026
Fixes the gap identified by Greptile: contracts saved before the
negation-lift rewrite retain the vacuously-false {"some": [var,
{"==": [field, null]}]} pattern in the database. Without this change
those contracts continue to report failed validation until the user
manually re-edits each rule. Applying getNegativeQueryForNotContainsReverserOperation
on load normalizes stale persisted rules the next time the contract
form is opened and saved.

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

github-actions Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Jest test Coverage

UI tests summary

Lines Statements Branches Functions
Coverage: 65%
65.67% (76784/116917) 49.52% (46069/93019) 50.75% (13889/27364)

Comment thread openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts Outdated
Comment thread openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts Outdated
Comment thread openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts Outdated
Comment thread openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts Outdated
…ll fix

Every guard added in response to a bot comment (form-load normalization,
live-edit confirmation, occurrence counting) immediately surfaced a new,
narrower edge case from the same bots, because none of them can be made
airtight without stable node identity linking the JsonLogic rule back to
its query-builder tree. The actual goal of this PR is unskipping the three
Owner/Domain/DataProduct Is_Not_Set Playwright tests, which only needs the
JsonLogic transform fix.

Reverted ContractSemanticFormTab.tsx/test.tsx and DataContractUtils.ts/test.ts
to main (dropping getNormalizedContractSemantics, isFieldUsingIsNullOperator,
createIsNullFieldConfirmation and the guard threading). Restored
getNegativeQueryForNotContainsReverserOperation to the original unconditional
rewrite for the is_null shape, consistent with how the existing
contains/in shapes are already handled unconditionally in the same
function — confirmed unambiguous by construction since the query builder
has no other path that emits that exact AST.

Normalizing already-persisted legacy contracts and reconciling the
Run Now validation path against unsaved form state are real gaps, but
they need a server-side fix and are out of scope for unskipping these
tests.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gitar-bot

gitar-bot Bot commented Jul 24, 2026

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

Corrects the "Is Not Set" JsonLogic evaluation for Owner, Domain, and DataProduct fields by lifting negations and unskips the associated Playwright tests. Consider addressing the minor finding where same-field rule rewrites could target the incorrect sibling.

✅ 3 resolved
Edge Case: Rules lacking a persisted jsonTree are not normalized

📄 openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts:97-111
Normalization only rewrites a broken some/==null rule when isFieldUsingIsNullOperator confirms the field via the persisted jsonTree. Contracts whose rule was authored via YAML/API (or older records persisted without a jsonTree) will not have a matching is_null tree node, so their vacuously-false "Is Not Set" rules remain broken and silently keep failing validation. This tradeoff is intentional per the code comments, but worth confirming that all affected legacy contracts actually carry a jsonTree; otherwise the fix will not reach them.

Edge Case: Load-time normalization guards ==null but not contains/in shapes

📄 openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts:97-111 📄 openmetadata-ui/src/main/resources/ui/src/utils/JSONLogicSearchClassBase.ts:819-833
getNormalizedContractSemantics now runs getNegativeQueryForNotContainsReverserOperation over every persisted rule at form load — a transform that previously only ran on builder edits. The new isConfirmedIsNullField guard only protects the some/==null branch; the some/!/contains and some/!/in branches are still rewritten unconditionally. A rule authored outside the builder (YAML/API) using that exact shape with genuine "some element does not contain X" intent would be silently reinterpreted as "not all elements contain X" on load. Consider extending an equivalent tree-confirmation guard to those branches, or scoping the load-time rewrite to the ==null case only.

Edge Case: Rewrite of same-field ==null rule may target the wrong sibling

📄 openmetadata-ui/src/main/resources/ui/src/utils/DataContract/DataContractUtils.ts:132-146 📄 openmetadata-ui/src/main/resources/ui/src/utils/JSONLogicSearchClassBase.ts
createIsNullFieldConfirmation consumes one is_null occurrence per field as processNotContains recurses. When a field has both a genuine 'Is Not Set' rule and a distinct hand-authored some/==null rule but fewer confirmed is_null tree nodes, the rewrite is applied to whichever candidate the traversal reaches first, which may be the hand-authored one — leaving the real 'Is Not Set' rule still broken and altering the other's semantics. The count-based guard bounds the number of rewrites but cannot associate a rewrite with its originating tree node. This is an acknowledged limitation (documented in the comment); if node identity ever becomes available, associating rules to tree nodes would resolve it. No action strictly required now.

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 👍 / 👎 | Gitar

Comment on lines +817 to 833
// Pattern generated by the "Is Not Set" (is_null) operator:
// {"some": [var, {"==": [field, null]}]}
const equalsNullArgs = condition?.['=='];
if (
Array.isArray(equalsNullArgs) &&
equalsNullArgs.length === 2 &&
equalsNullArgs[1] === null
) {
const [field] = equalsNullArgs;

return {
'!': {
some: [variable, { '!=': [field, null] }],
},
};
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Persisted rules remain unnormalized

When a user runs validation on an existing contract containing a legacy Owner, Domain, or DataProduct some/==null rule without editing and saving that rule first, this query-builder transformation never runs. Run Now therefore evaluates the unchanged persisted expression, causing a genuinely unset grouped field to report failed contract validation.

@sonarqubecloud

Copy link
Copy Markdown

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant