Skip to content

fix(check-saved-objects): treat text→keyword field downgrade as a newly introduced problem#260499

Merged
gsoldevila merged 2 commits intoelastic:mainfrom
gsoldevila:fix/check-so-changes-text-to-keyword-regression
Apr 1, 2026
Merged

fix(check-saved-objects): treat text→keyword field downgrade as a newly introduced problem#260499
gsoldevila merged 2 commits intoelastic:mainfrom
gsoldevila:fix/check-so-changes-text-to-keyword-regression

Conversation

@gsoldevila
Copy link
Copy Markdown
Member

Summary

Follow-up to #260280, addressing the edge case raised in this review comment.

The bug

The pre-existing vs. newly-introduced classification in validateNameTitleFieldTypesExistingType was based on whether the field key was present in the baseline snapshot ('properties.name.type' in from.mappings). This correctly catches absent → keyword, but silently misclassifies text → keyword as pre-existing — because the key is already in from.mappings, even though the field was previously valid.

The result: a developer who downgrades a name/title field from text to keyword gets no warning and no failure from the CI check.

The fix

Both preExisting and newlyIntroduced are now derived from the set of fields that were already invalid in from, not merely present:

const alreadyInvalidInFrom = new Set(
  getInvalidNameTitleFields(from).map(({ fieldName }) => fieldName)
);
const preExisting     = invalidInTo.filter(({ fieldName }) =>  alreadyInvalidInFrom.has(fieldName));
const newlyIntroduced = invalidInTo.filter(({ fieldName }) => !alreadyInvalidInFrom.has(fieldName));

This handles all four scenarios correctly:

from type to type Result
absent keyword ❌ fail (newly introduced)
text keyword ❌ fail (newly introduced — was this PR's bug)
keyword keyword ⚠️ warn (pre-existing, cannot be fixed without reindex)
keyword text ✅ nothing (fixed)

Test plan

  • New test 'should throw when a name or title field is downgraded from text to keyword' in existing_type.test.ts covers the regression case
  • All 40 tests in the validate_changes suite pass

Made with Cursor

…ly introduced problem

Previously, the pre-existing vs. newly-introduced distinction for name/title field type
checks was based on whether the field key was present in the baseline snapshot. This caused
a regression where a field downgraded from 'text' to 'keyword' was silently classified as
pre-existing (key already present) instead of being caught as a new problem.

The fix derives both categories consistently from invalidity in the baseline: a field is
pre-existing only if it was already invalid (non-text) in the 'from' snapshot. A field that
was valid (text) or absent before but is now invalid (keyword) is always treated as newly
introduced and triggers a hard failure.

Adds a dedicated test covering the text→keyword downgrade case.

Made-with: Cursor
@gsoldevila gsoldevila added Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t// release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting labels Mar 31, 2026
@gsoldevila gsoldevila marked this pull request as ready for review March 31, 2026 15:27
@gsoldevila gsoldevila requested a review from a team as a code owner March 31, 2026 15:27
@elasticmachine
Copy link
Copy Markdown
Contributor

Pinging @elastic/kibana-core (Team:Core)

Copy link
Copy Markdown
Contributor

@hammad-nasir-elastic hammad-nasir-elastic left a comment

Choose a reason for hiding this comment

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

Nice! LGTM

@gsoldevila gsoldevila enabled auto-merge (squash) March 31, 2026 15:31
@gsoldevila gsoldevila merged commit cc469e7 into elastic:main Apr 1, 2026
18 checks passed
@elasticmachine
Copy link
Copy Markdown
Contributor

💚 Build Succeeded

Metrics [docs]

✅ unchanged

History

jeramysoucy pushed a commit to jeramysoucy/kibana that referenced this pull request Apr 1, 2026
…ly introduced problem (elastic#260499)

## Summary

Follow-up to elastic#260280, addressing the edge case raised in [this review
comment](https://github.com/elastic/kibana/pull/260280/changes/BASE..8b520af6534a998b849dd3567b3b659c470e60ea#r3016163498).

### The bug

The pre-existing vs. newly-introduced classification in
`validateNameTitleFieldTypesExistingType` was based on whether the field
*key* was present in the baseline snapshot (`'properties.name.type' in
from.mappings`). This correctly catches `absent → keyword`, but silently
misclassifies `text → keyword` as pre-existing — because the key is
already in `from.mappings`, even though the field was previously valid.

The result: a developer who downgrades a `name`/`title` field from
`text` to `keyword` gets no warning and no failure from the CI check.

### The fix

Both `preExisting` and `newlyIntroduced` are now derived from the set of
fields that were **already invalid in `from`**, not merely present:

```ts
const alreadyInvalidInFrom = new Set(
  getInvalidNameTitleFields(from).map(({ fieldName }) => fieldName)
);
const preExisting     = invalidInTo.filter(({ fieldName }) =>  alreadyInvalidInFrom.has(fieldName));
const newlyIntroduced = invalidInTo.filter(({ fieldName }) => !alreadyInvalidInFrom.has(fieldName));
```

This handles all four scenarios correctly:

| `from` type | `to` type | Result |
|---|---|---|
| absent | `keyword` | ❌ fail (newly introduced) |
| `text` | `keyword` | ❌ fail (newly introduced — was this PR's bug) |
| `keyword` | `keyword` | ⚠️ warn (pre-existing, cannot be fixed without
reindex) |
| `keyword` | `text` | ✅ nothing (fixed) |

## Test plan

- [ ] New test `'should throw when a name or title field is downgraded
from text to keyword'` in `existing_type.test.ts` covers the regression
case
- [ ] All 40 tests in the `validate_changes` suite pass

Made with [Cursor](https://cursor.com)
eokoneyo pushed a commit to davismcphee/kibana that referenced this pull request Apr 2, 2026
…ly introduced problem (elastic#260499)

## Summary

Follow-up to elastic#260280, addressing the edge case raised in [this review
comment](https://github.com/elastic/kibana/pull/260280/changes/BASE..8b520af6534a998b849dd3567b3b659c470e60ea#r3016163498).

### The bug

The pre-existing vs. newly-introduced classification in
`validateNameTitleFieldTypesExistingType` was based on whether the field
*key* was present in the baseline snapshot (`'properties.name.type' in
from.mappings`). This correctly catches `absent → keyword`, but silently
misclassifies `text → keyword` as pre-existing — because the key is
already in `from.mappings`, even though the field was previously valid.

The result: a developer who downgrades a `name`/`title` field from
`text` to `keyword` gets no warning and no failure from the CI check.

### The fix

Both `preExisting` and `newlyIntroduced` are now derived from the set of
fields that were **already invalid in `from`**, not merely present:

```ts
const alreadyInvalidInFrom = new Set(
  getInvalidNameTitleFields(from).map(({ fieldName }) => fieldName)
);
const preExisting     = invalidInTo.filter(({ fieldName }) =>  alreadyInvalidInFrom.has(fieldName));
const newlyIntroduced = invalidInTo.filter(({ fieldName }) => !alreadyInvalidInFrom.has(fieldName));
```

This handles all four scenarios correctly:

| `from` type | `to` type | Result |
|---|---|---|
| absent | `keyword` | ❌ fail (newly introduced) |
| `text` | `keyword` | ❌ fail (newly introduced — was this PR's bug) |
| `keyword` | `keyword` | ⚠️ warn (pre-existing, cannot be fixed without
reindex) |
| `keyword` | `text` | ✅ nothing (fixed) |

## Test plan

- [ ] New test `'should throw when a name or title field is downgraded
from text to keyword'` in `existing_type.test.ts` covers the regression
case
- [ ] All 40 tests in the `validate_changes` suite pass

Made with [Cursor](https://cursor.com)
paulinashakirova pushed a commit to paulinashakirova/kibana that referenced this pull request Apr 2, 2026
…ly introduced problem (elastic#260499)

## Summary

Follow-up to elastic#260280, addressing the edge case raised in [this review
comment](https://github.com/elastic/kibana/pull/260280/changes/BASE..8b520af6534a998b849dd3567b3b659c470e60ea#r3016163498).

### The bug

The pre-existing vs. newly-introduced classification in
`validateNameTitleFieldTypesExistingType` was based on whether the field
*key* was present in the baseline snapshot (`'properties.name.type' in
from.mappings`). This correctly catches `absent → keyword`, but silently
misclassifies `text → keyword` as pre-existing — because the key is
already in `from.mappings`, even though the field was previously valid.

The result: a developer who downgrades a `name`/`title` field from
`text` to `keyword` gets no warning and no failure from the CI check.

### The fix

Both `preExisting` and `newlyIntroduced` are now derived from the set of
fields that were **already invalid in `from`**, not merely present:

```ts
const alreadyInvalidInFrom = new Set(
  getInvalidNameTitleFields(from).map(({ fieldName }) => fieldName)
);
const preExisting     = invalidInTo.filter(({ fieldName }) =>  alreadyInvalidInFrom.has(fieldName));
const newlyIntroduced = invalidInTo.filter(({ fieldName }) => !alreadyInvalidInFrom.has(fieldName));
```

This handles all four scenarios correctly:

| `from` type | `to` type | Result |
|---|---|---|
| absent | `keyword` | ❌ fail (newly introduced) |
| `text` | `keyword` | ❌ fail (newly introduced — was this PR's bug) |
| `keyword` | `keyword` | ⚠️ warn (pre-existing, cannot be fixed without
reindex) |
| `keyword` | `text` | ✅ nothing (fixed) |

## Test plan

- [ ] New test `'should throw when a name or title field is downgraded
from text to keyword'` in `existing_type.test.ts` covers the regression
case
- [ ] All 40 tests in the `validate_changes` suite pass

Made with [Cursor](https://cursor.com)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes Team:Core Platform Core services: plugins, logging, config, saved objects, http, ES client, i18n, etc t// v9.4.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants