Skip to content

Add Warning Modal for Expansion on Constraint Violation#1956

Open
pranav-super wants to merge 19 commits into
developfrom
feature/disable-expansion-on-constraint-viol
Open

Add Warning Modal for Expansion on Constraint Violation#1956
pranav-super wants to merge 19 commits into
developfrom
feature/disable-expansion-on-constraint-viol

Conversation

@pranav-super

@pranav-super pranav-super commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

___REQUIRES_AERIE_PR___="1837"

This PR introduces a warning modal when a planner attempts to expand a sequence while there are still outstanding constraint violations. This feature was introduced based on a request by LRO mission operators.

Generally, the idea is to only warn users, but not to block anything. As constraint status is slightly nuanced, the following conditions are considered.

  • If simulation is out of date (i.e. the plan has been modified), the planner will be warned that their constraints may be outdated, and that expansion results could be misleading, as expansion will be done on the previous simulation, which may not match the current plan's status.
    • There is an additional modification made to the expansion disabling functionality, stating that if the simulation is out of date, expansion is disabled. This can be undone, but was proposed in ExpansionPanel.svelte.
  • If constraint evaluation failed (not a violation, but failure to even evaluate), or incomplete, the planner is similarly warned.
  • If there are unchecked (or disabled, as PlanDev treats them the same in the UI) constraints, the planner should be warned that the current constraint evaluation may not be exhaustive.
  • If there are violated constraints, the planner should be warned that they are about to expand in spite of constraints that are failing.

Other statuses of constraints, like their being out of date (considered unchecked), partially complete, or anything else are not considered here.

Furthermore, the boolean argument bypassConstraints was added to calls to expandTemplates, in conjunction with an update to the backend which would throw errors on expansion if there were a violation and the bypass was not set. The default in the UI (and in the backend) is to not throw errors and bypass, as a warning is sufficient.

export let constraintToConstraintResponseMap: ConstraintInvocationMap<ConstraintResponse>;
export let simulationDatasetId: number;

// TODO: adjust dynamically?

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.

Would be better to just set a more generous height and the modal scroll on overflow since I'm seeing this sort of thing. Don't think dynamic height is worth complexity since at some point you're going to have to scroll anyway once you reach the full screen width (if you have lots of constraint issues).

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

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.

Regarding this - any reason not to call these constraints out as being out of date vs unchecked? Complexity or is it hard to be certain of the status?

Other statuses of constraints, like their being out of date (considered unchecked), partially complete, or anything else are not considered here.

@pranav-super pranav-super Jul 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think it was primarily to reduce the amount of information in this modal (and subsequently decrease implementation complexity). If this modal completely repeated all the information, it would be sort of redundant with respect to the existing constraints panel.

I was going for conciseness here, but does that seem reasonable?

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.

Is it expected that if a constraint fails to compile (StayWellFed in this example below), it will not appear in the list of issues?

Image

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Now that I think about it, that might be worth mentioning as a failure of sorts! I say "of sorts" because while this is unexpected behavior and I agree with the implication that this probably should be presented in a warning, my question is about how concise we should be, and how to concisely present this!

<p>The following constraints were violated:</p>
<div class="constraints-list">
{#each failingConstraints as failing}
<p>{failing.name} <b>({failing.viols} violations)</b></p>

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.

Can we properly pluralize violation(s)? Have a pluralize util that we use for this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

} else {
isExpansionDisabled = true;
expansionDisabledMessage = 'Completed simulation required';
// Question for PlanDev team: should we include this? Or only in the modal.

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.

Any reason not to block before the modal? Is there any reason to open that modal before you have an up to date sim?

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.

Also i seem to be able to open the modal and expand with an out of date sim

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.

Ah - i see this happens only when i have no constraint violations, then I see the out of date sim message. Should stale sim be the first error precedence wise? Not totally sure, but should think on that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

What would all the cases be? Right now it's:

  • simulation is out of date -> not disabling because we can expand on an old simulation (?)
  • simulation is incomplete -> disabling, as we are trying to expand on the current simulation but cannot
  • no relevant sequences -> disabling, as we can't expand into anything
  • using templating -> not disabling...should still execute the functionality. This was something I left from before this PR
  • using sequencing -> depends; this logic was something I left from before this PR

: $checkConstraintsStatus === Status.Incomplete
? ' (incomplete evaluation)'
: uncheckedConstraints.length > 0 || failingConstraints.length > 0
? ` (${uncheckedConstraints.length > 0} unchecked, ${failingConstraints.length > 0} failed)`

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.

want length not the boolean here for uncheckedConstraints.length > 0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

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.

Have some language suggestions here:

Titles:

  • Failed -> "Constraints could not be evaluated"
  • Incomplete -> "Constraint evaluation incomplete"
  • Out of date -> "Simulation is out of date"
  • Unchecked -> "Unchecked constraints"
  • Violations -> "Constraint violations"

Body, by state:

  • Failed: "The most recent constraint evaluation failed, so the current constraint status is unknown."
  • Incomplete: "The most recent constraint evaluation didn't finish, so the current constraint status is incomplete."
  • Out of date: "The plan has changed since the last simulation, so the constraint results in the Constraints panel no longer reflect the current plan."

The constraint lists - can we render them as actual bulleted lists rather than stacked paragraphs and when the results are stale (eval failed/incomplete or sim out of date) preface them so it's clear they're from the last run:

  • Unchecked: "These constraints haven't been checked and may be violated:" (or "From the last evaluation, these constraints haven't been checked and may be violated:" when stale)
  • Violated: "These constraints are currently violated:" (or "The last evaluation found violations in these constraints:" when stale), with each entry pluralized properly — "(1 violation)" / "(2 violations)".

Closing line - one bolded statement of the actual risk, then the question:

  • For the out-of-date case: "Expansion will run against the previous simulation and may not match the current plan."
  • Otherwise: "Expanding now may produce sequences that violate mission constraints."
  • Then: "Do you want to expand anyway?"

I'd also relabel the "Expand" primary button in the modal to be "Expand anyway" and I'd make it destructive red (matching ConfirmModal).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This update has been made! The existing verbiage has been updated, though some of the other unreachable states you mentioned in other comments haven't been inserted.


let warningMessage = '';

$: if ($checkConstraintsStatus === Status.Failed) {

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.

Need to handle Incomplete and Canceled?

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.

For incomplete + canceled it'll just fall through to "Violating Constraints"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Those cases shouldn't trigger this modal, owing to the condition in onExpandSequence in ExpansionPanel.svelte.

Comment thread src/utilities/gql.ts Outdated
$seqIds: [String!]!,
$modelId: Int!,
$simulationDatasetId: Int!
$bypassConstraints: Bool

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.

Bool -> Boolean

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

} else if (selectedExpansionSetId !== null) {
effects.expand(selectedExpansionSetId, $simulationDatasetLatest.id, $plan, user);
async function onExpandSequence(sequence: ExpansionSequence) {
var result = { confirm: true };

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.

Any reason not to just get the result of confirm modal within that if block and if confirm is false just return early? Wouldn't have to gate the following logic in if (result.confirm)...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this is related to the earlier question of what to throw the modal up for. I also think what you're saying makes sense, but the idea here was to only show this modal in a subset of relevant scenarios (constraint checking was unsuccessful, simulation is out of date, or constraints weren't checked/failed). In any other scenarios, we wouldn't show the modal, as doing so might imply that the modal needs to convey extra information that could be redundant with what's already in the panel. This way, we only warn when we really need to (expansion on violation), but allow expansion otherwise.

if (SEQUENCE_EXPANSION_MODE === SequencingMode.TEMPLATING) {
effects.expandTemplates([sequence.seq_id], $simulationDatasetLatest.id, $plan, user);
} else if (selectedExpansionSetId !== null) {
effects.expand(selectedExpansionSetId, $simulationDatasetLatest.id, $plan, user);

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.

Does effects.expand need this bypassConstraints flag wired in as well?

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.

Bigger point - why is this only applied to template expansion?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

bypassConstraints is only really applicable/used when expansion is attempted without the UI. We wanted some way of allowing the backend to also pose this prevention (quick link to the PR), and since that endpoint is what expansion invokes, added the boolean there. It would always be set to true though, as we only want a warning modal and then no other protections. But if a CLI was implemented where they wanted that block, it would be possible to do so. I guess we could remove it altogether from effects...

The logic of only applying things to template expansion is not new to this PR though, but I'm not entirely sure what you mean!

}
}

// copied from ConstraintsPanel. Unable to move this into a store, as ConstraintsPanel directly modifies startTime, though we do not need to here.

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.

Could we move this logic into a util that takes (specs, responseMap, startMs, endMs)?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I did try extracting it into a store earlier, but I believe I ran into an issue with startTime being modified in the ConstraintsPanel equivalent (though that is something we wouldn't want here). I think the same issue would arise in extracting it to a utility function!

I updated the comment to clarify that this is modified from ConstraintsPanel, not a direct copy. However, would it be worth breaking this into functions and reorganizing within ExpansionPanel itself?

placement: 'top',
}}
>
<!-- <button

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.

Dead code?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

});
}

let allConstraintsHaveBeenChecked = true;

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.

Can these lets be declared at the top of the file with the other lets? Also don't we need to reset these two allConstraints... booleans back to true at the start of the reactive block below since the &&= will only update these two variables if the left hand side is truthy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed!

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@pranav-super pranav-super force-pushed the feature/disable-expansion-on-constraint-viol branch from 8f5637e to 23a0fc3 Compare July 9, 2026 18:17
@sonarqubecloud

sonarqubecloud Bot commented Jul 9, 2026

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
15.8% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants