Conversation
…nto gap-reason-detected
…tion_tests/ci_checks
…nto gap-reason-detected
|
/ci |
|
@elasticmachine merge upstream |
|
There are no new commits on the base branch. |
|
/ci |
…tion_tests/ci_checks
…mportable/exportable SO types (elastic#260280) ## Summary Closes elastic/kibana-team#3162 The \`validateNameTitleFieldTypes\` check in \`kbn-check-saved-objects-cli\` enforces that any SO type with a \`name\` or \`title\` mapping field must use \`type: text\`, citing Search API compatibility. There are two distinct cases where the check was incorrect: ### Case 1: Types not searchable via the management page The check was applied unconditionally to all SO types, but the Saved Objects management page search only queries types where \`management.importableAndExportable === true\`. The registry treats the absence of that flag as \`false\`, so types without it set are never included in management search and the full-text requirement does not apply to them. Flagging such types also creates pressure to change \`keyword\` → \`text\`, which is a **breaking Elasticsearch mapping change** (reindex required) that is entirely unnecessary. Note: the \`hidden\` flag alone is **not** the right exemption criterion — the management find route explicitly includes hidden types that are also \`importableAndExportable: true\` (via \`includedHiddenTypes\`), so those remain subject to the check. ### Case 2: Pre-existing keyword fields from shipped model versions Even for importable/exportable types, if \`name\` or \`title\` was already shipped as \`keyword\` in a previous model version, **there is nothing the developer can do to fix it** without a full reindex. Failing the CI check in this case blocks the PR with no actionable resolution. ## Changes - Split \`validateNameTitleFieldTypes\` into two focused functions: - \`validateNameTitleFieldTypesNewType\` (in \`new_type_utils.ts\`) — throws for any wrong field type on importable/exportable types; no baseline exists for new types so the full error always applies - \`validateNameTitleFieldTypesExistingType\` (in \`existing_type_utils.ts\`) — warns for pre-existing wrong field types, fails only for newly introduced ones - Shared helpers \`getInvalidNameTitleFields\` and \`isSearchableViaManagement\` extracted to \`common_utils.ts\` - Exemption condition uses \`!== true\` (not \`=== false\`) to also cover types where \`management\` is absent, matching the registry's \`?? false\` default - \`createMockType\` in tests now defaults to \`importableAndExportable: true\` so the positive (participates-in-management-search) path is exercised correctly - Tests updated: exemption test covers \`importableAndExportable: false\`; a new test confirms that hidden types with \`importableAndExportable: true\` are still subject to the check ## Context This was first surfaced by elastic#260095, which adds model version 2 to \`gap_auto_fill_scheduler\` — a type with \`importableAndExportable\` not set to \`true\` and a pre-existing \`name: keyword\` mapping from model version 1. ## Test plan - [ ] Existing tests in \`new_type.test.ts\` still pass - [ ] Tests in \`existing_type.test.ts\` confirm: warning for pre-existing keyword fields, fail for newly introduced ones, exempt for non-importable/exportable types, and fail for hidden types that are importable/exportable --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
darnautov
left a comment
There was a problem hiding this comment.
Overall LGTM, just one concern about duplicating excludedReasons schema
| excludedReasons: schema.maybe( | ||
| schema.arrayOf( | ||
| schema.oneOf([ | ||
| schema.literal(gapReasonType.RULE_DISABLED), | ||
| schema.literal(gapReasonType.RULE_DID_NOT_RUN), | ||
| ]), | ||
| { maxSize: Object.values(gapReasonType).length } | ||
| ) |
There was a problem hiding this comment.
I noticed it's been duplicated in other schemas, should we consolidate it?
maximpn
left a comment
There was a problem hiding this comment.
@nkhristinin Thanks for addressing my comments 🙏
I've tested the functionality locally. It works as expected.
There are a couple of comments related to my previous comments regarding exclude reasons schema and deduplication. These should be easy to address. Besides that it looks good so approving.
| schema.oneOf([ | ||
| schema.literal(gapReasonType.RULE_DISABLED), | ||
| schema.literal(gapReasonType.RULE_DID_NOT_RUN), | ||
| ]) |
There was a problem hiding this comment.
| ]) | |
| ]), | |
| { | |
| maxSize: Object.values(gapReasonType).length, | |
| } |
| const excludedReasonsFilter = | ||
| excludedReasons && excludedReasons.length > 0 | ||
| ? `NOT (${excludedReasons | ||
| .map((reason) => `${GAP_REASON_TYPE_FIELD}: "${reason}"`) | ||
| .join(' OR ')})` | ||
| : null; |
There was a problem hiding this comment.
Let's have excluded reasons deduplication. Typing doesn't prevent having an array with the same values.
| const excludedReasonsFilter = | |
| excludedReasons && excludedReasons.length > 0 | |
| ? `NOT (${excludedReasons | |
| .map((reason) => `${GAP_REASON_TYPE_FIELD}: "${reason}"`) | |
| .join(' OR ')})` | |
| : null; | |
| const excludedReasonsSet = new Set(excludedReasons ?? []); | |
| const excludedReasonsFilter = | |
| excludedReasonsSet.size > 0 | |
| ? `NOT (${Array.from(excludedReasonsSet) | |
| .map((reason) => `${GAP_REASON_TYPE_FIELD}: "${reason}"`) | |
| .join(' OR ')})` | |
| : null; |
…mportable/exportable SO types (elastic#260280) ## Summary Closes elastic/kibana-team#3162 The \`validateNameTitleFieldTypes\` check in \`kbn-check-saved-objects-cli\` enforces that any SO type with a \`name\` or \`title\` mapping field must use \`type: text\`, citing Search API compatibility. There are two distinct cases where the check was incorrect: ### Case 1: Types not searchable via the management page The check was applied unconditionally to all SO types, but the Saved Objects management page search only queries types where \`management.importableAndExportable === true\`. The registry treats the absence of that flag as \`false\`, so types without it set are never included in management search and the full-text requirement does not apply to them. Flagging such types also creates pressure to change \`keyword\` → \`text\`, which is a **breaking Elasticsearch mapping change** (reindex required) that is entirely unnecessary. Note: the \`hidden\` flag alone is **not** the right exemption criterion — the management find route explicitly includes hidden types that are also \`importableAndExportable: true\` (via \`includedHiddenTypes\`), so those remain subject to the check. ### Case 2: Pre-existing keyword fields from shipped model versions Even for importable/exportable types, if \`name\` or \`title\` was already shipped as \`keyword\` in a previous model version, **there is nothing the developer can do to fix it** without a full reindex. Failing the CI check in this case blocks the PR with no actionable resolution. ## Changes - Split \`validateNameTitleFieldTypes\` into two focused functions: - \`validateNameTitleFieldTypesNewType\` (in \`new_type_utils.ts\`) — throws for any wrong field type on importable/exportable types; no baseline exists for new types so the full error always applies - \`validateNameTitleFieldTypesExistingType\` (in \`existing_type_utils.ts\`) — warns for pre-existing wrong field types, fails only for newly introduced ones - Shared helpers \`getInvalidNameTitleFields\` and \`isSearchableViaManagement\` extracted to \`common_utils.ts\` - Exemption condition uses \`!== true\` (not \`=== false\`) to also cover types where \`management\` is absent, matching the registry's \`?? false\` default - \`createMockType\` in tests now defaults to \`importableAndExportable: true\` so the positive (participates-in-management-search) path is exercised correctly - Tests updated: exemption test covers \`importableAndExportable: false\`; a new test confirms that hidden types with \`importableAndExportable: true\` are still subject to the check ## Context This was first surfaced by elastic#260095, which adds model version 2 to \`gap_auto_fill_scheduler\` — a type with \`importableAndExportable\` not set to \`true\` and a pre-existing \`name: keyword\` mapping from model version 1. ## Test plan - [ ] Existing tests in \`new_type.test.ts\` still pass - [ ] Tests in \`existing_type.test.ts\` confirm: warning for pre-existing keyword fields, fail for newly introduced ones, exempt for non-importable/exportable types, and fail for hidden types that are importable/exportable --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
denar50
left a comment
There was a problem hiding this comment.
Thanks for addressing my comments, I tested locally. LGTM!
| "items": { | ||
| "type": "keyword", | ||
| "_meta": { | ||
| "description": "Non-default value of setting." |
There was a problem hiding this comment.
Can you improve this description? We hope to one day use these descriptions as documentation in Telemetry.
|
@elasticmachine merge upstream |
💚 Build Succeeded
Metrics [docs]Module Count
Public APIs missing comments
Any counts in public APIs
Async chunks
Page load bundle
Unknown metric groupsAPI count
History
cc @nkhristinin |
Gap Reason UI
Overview
This PR adds API-level filtering by gap reason and the Rule Settings UI for controlling which gap reasons are included in gap monitoring and auto-fill. The gap reason detection logic and the "Reason" column in the gaps table were shipped in a previous PR (#258231).
CleanShot.2026-03-29.at.20.48.11.mp4
Feature Flag
Gated behind
gapReasonDetectionEnabled(default:false). When disabled:excludedReasonsstill works at the schema level but has no practical effect since no reasons are writtenChanges
Rule Settings Modal
excludedReasonsto both the gap auto-fill scheduler saved object andsecuritySolution:excludedGapReasonsUI setting. The value is stored in two places because the gap auto-fill scheduler can be available for people with free tiers.Bulk Fill Modal
rule_disabledgaps are excluded: "Gaps caused by disabled rules will not be filled. You can change this in Rule Settings."Gap table
Add reason filter which by default get values from the rule setting modal
API Filtering
getRuleIdsWithGaps— acceptsexcluded_reasonsparameter to filter out gaps by reason typegetGapsSummaryByRuleIds— acceptsexcluded_reasonsparameter for summary calculationsfindRulesroute — readsEXCLUDED_GAP_REASONS_KEYfrom UI settings and passes it to gap filteringexcludedReasonswhen scheduling gap fillsexcludedReasons(persisted in saved object)buildGapsFilter— extended to support reason-based filtering in ES queriesUI Settings
securitySolution:excludedGapReasons— new advanced setting (readonly, array type) controlling which gap reasons are excluded from monitoring and auto-fill. Default:['rule_disabled']How to Test
Prerequisites
kibana.dev.yml:Test 1:
rule_disabledreasonTest 2:
rule_did_not_runreason (Kibana downtime)