[Alerting V2] [ResponseOps] Recovery delay is configurable and persisted even when it has no effect on execution - #288802
Conversation
|
Pinging @elastic/response-ops (Team:ResponseOps) |
baileycash-elastic
left a comment
There was a problem hiding this comment.
looks good, one rec on the naming for the isRecoveryDelayAllowed naming. I realized we'll have UI work to do so I'll raise a separate ticket and race you! :D
| expect(result.success).toBe(false); | ||
| }); | ||
|
|
||
| it('accepts recovering_count of 0 when recovery is disabled', () => { |
There was a problem hiding this comment.
I can change this if needed, it is kind of weird
There was a problem hiding this comment.
I was trying to minimize the disruption from adding the new validation
There was a problem hiding this comment.
might create some drift since I plan to hide the ui field entirely, we'll see. I want to avoid over-engineering the mapper if possible
There was a problem hiding this comment.
Okay yeah that makes sense, I can remove it
| }); | ||
|
|
||
| it('returns true when recovery is disabled but no recovering delay is set', () => { | ||
| expect(isRecoveryDelayAllowed({ recovery_strategy: 'none' })).toBe(true); |
There was a problem hiding this comment.
isRecoveryDelayAllowed feels slightly misleading in this case
So sorry, backend changes look good... a few naming conventions I thought were a little weird.
The UI changes are still needed, best to do here to avoid any problems. Thanks for making these changes!
…thub.com:doakalexi/kibana into alerting-v2/update-validation-for-recovery-delay
|
@baileycash-elastic I added UI changes in this commit, 9b736cc |
…thub.com:doakalexi/kibana into alerting-v2/update-validation-for-recovery-delay
…ate-validation-for-recovery-delay
There was a problem hiding this comment.
One compatibility concern on the update path: the new isRecoveryTransitionConsistentWithStrategy invariant runs on every update against merged attributes, which can make pre-existing rules that carry an inert recovering delay un-updatable. Details inline. The rest of the change (schema refinement, form/compose mappers gating on isRecoveryEnabled, agent-builder op check, error code, and the accompanying tests) looks consistent and well-covered.
Generated by Claude Reviewer for #288802 · claude · opus · 368.7 AIC · ⌖ 22.6 AIC · ⊞ 5.5K
| details: { rule_id: ruleId }, | ||
| }, | ||
| { | ||
| valid: isRecoveryTransitionConsistentWithStrategy(attrs), |
There was a problem hiding this comment.
This invariant runs on every updateRule call (validateMergedRuleAttributes(id, nextAttrs) is unconditional), and nextAttrs preserves the stored state_transition/recovery_strategy when the update body doesn't touch them. That makes it a backward-compatibility concern for rules already in storage.
Before this PR, createRuleDataSchema had no recovering-vs-strategy refinement, and the old form mapper emitted recovering_count: 0 unconditionally for immediate recovery mode (see the assertions removed in rule_request_mappers.test.ts). So a rule with recovery_strategy: 'none'/unset + state_transition.recovering_count: 0 (or a positive value) was createable via both the API and the UI and can exist on disk today.
After this change, any such pre-existing rule becomes un-updatable: even an unrelated PATCH (e.g. renaming) merges to the same inert recovering delay and now throws INVALID_STATE_TRANSITION_CONFIG (400), forcing the user to clear the recovering delay in the same request before any other edit can go through.
If alerting_v2 already has persisted rules in this shape, consider normalizing the inert recovering fields out of nextAttrs on update (drop them when recovery is disabled) rather than rejecting, or adding a saved-object migration to strip them — so existing rules stay editable. If there's no such data yet (pre-GA, no migration needed), it'd be worth confirming that explicitly.
There was a problem hiding this comment.
This is okay because we are experimental.
baileycash-elastic
left a comment
There was a problem hiding this comment.
lgtm, proposed a few areas to 🧹 clean
tysm for implementing this!
|
|
||
| <EuiSpacer size="m" /> | ||
| <RecoveryDelayField /> | ||
| {/* |
There was a problem hiding this comment.
nit: self-explanatory, comment not needed
| if (stateTransition?.recoveringTimeframe != null) | ||
| out.recovering_timeframe = stateTransition.recoveringTimeframe; | ||
| if (stateTransition?.recoveringCount != null) | ||
| // Recovering thresholds are only meaningful when recovery is enabled; emitting them |
There was a problem hiding this comment.
nit: self explanatory
| /** | ||
| * Recovery is enabled only for condition-based strategies (`no_breach` / `query`). | ||
| * `none`/unset means condition-based recovery never fires, so the recovering delay | ||
| * thresholds (`recovering_count` / `recovering_timeframe`) are inert and must not be | ||
| * emitted — the write API rejects them (see `isRecoveryTransitionConsistentWithStrategy`). | ||
| * `no_data_strategy: 'recover'` does NOT re-enable them: the director bypasses recovering | ||
| * gating for no-data recovery (see `count_timeframe_strategy`). | ||
| */ |
There was a problem hiding this comment.
probably not needed
…rror_codes.ts Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
…_v2/common/builders.ts Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
💛 Build succeeded, but was flaky
Failed CI Steps
Metrics [docs]Page load bundle
Unknown metric groupstotal optimizer output size
warm start memory
History
|
Resolves #279941
Summary
Recovery delay (state_transition.recovering_count / state_transition.recovering_timeframe) only ever does real work when a recovery strategy is enabled. This PR updates the schema validation on create/update to not allow creating a rule with state_transition.recovering_count > 0 / state_transition.recovering_timeframe when the recovery_strategy is null or undefined.
Note: the validation does allow
recovering_count: 0it is not a delay and the episode will recover immediately. I'm happy to change this if that is confusing.Checklist
To verify
Verify
recovery_strategy: "none"+recovering_count > 0failsVerify
recovery_strategyunset +recovering_timeframefailsVerify it still fails with
no_data_strategy: "recover"Verify
recovering_count: 0is allowed even when recovery is disabledVerify pending-only
state_transitionis allowed while recovery is disabledVerify a recovery delay is allowed with recovery enabled
Keep the
idfrom the response for the next sectionUpdate the rule above to disable recovery without clearing the delay, expect
400Update the rule to disable recovery with also clearing the delay, expect
200