Claim the prompt surface only when a modal will show - #9387
Draft
catalinradoiu wants to merge 1 commit into
Draft
Conversation
Evaluators decided and showed in a single evaluate() call, so the Modal Coordinator had to claim the shared prompt surface speculatively, before knowing whether any modal would show. Most passes showed nothing and released the claim milliseconds later, but an NTP card claiming in that window was refused, and tryClaim papered over it by waiting a second and retrying. Split the two: evaluate() now returns WantsToShow with a deferred show action, evaluation runs with no claim held, and the surface is claimed only once an evaluator is about to show. A claim now always means a prompt is genuinely appearing, so a busy surface is a final answer and the wait/retry in tryClaim is gone. Side effects that mark a prompt as consumed (RMF message recorded, survey marked shown, default browser stage advanced) moved into the show action, so a refused claim can no longer burn a prompt nobody saw. The two promo evaluators resolve their display delay and presenter lookup during evaluation, since both can still decline. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
|
Contributor
|
Code looks good to me. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Task/Issue URL:
Tech Design URL (if applicable):
API Proposals URL(s) (if applicable):
Description
Introduces a decide-then-show contract for modal evaluators. Previously,
evaluate()was responsible for both deciding eligibility and performing the side effects of showing a modal (marking surveys consumed, recording messages shown, advancing prompt stages, starting activities). This meant that side effects could fire before the shared prompt surface was actually claimed, and a refused surface could silently burn a prompt or advance state without anything ever appearing on screen.The
ModalEvaluator.EvaluationResult.ModalShownresult type is replaced byWantsToShow(show: suspend () -> Boolean). Evaluators now return a deferred action:evaluate()is side-effect free with respect to showing, and the coordinator invokesshow()only after successfully claiming the shared prompt surface. Theshow()lambda returnstruewhen the modal actually reached the user andfalsewhen showing fell through (e.g. no visible host), allowing the coordinator to cancel the claim and continue down the priority list rather than recording a completion.The
PromptsCoordinatorclaim model is simplified accordingly. Because claims are now never speculative — a claim is taken only when a modal is definitely about to show — a busy surface is a final answer rather than something to wait out. The 1-second wait-and-retry loop inRealPromptsCoordinator.tryClaimis removed, along with theMutableStateFlowowner and theClaimOutcomesealed interface. The owner is now a plain nullable field guarded by the existing mutex.Stage transitions in
AdditionalDefaultBrowserPromptsImplare deferred into the show action so that a refused prompt surface cannot advance the stage without its dialog ever appearing. Similarly, survey consumption inDefaultBrowserChangedSurveyEvaluatorand message recording inRemoteMessageModalSurfaceEvaluatorare moved inside their respective show actions.Tests are updated throughout to reflect the two-phase contract: assertions verify that deciding alone produces no side effects, and side effects are confirmed only after explicitly invoking the returned
show()action.Steps to test this PR
Modal prompt coordination
show()action is never invoked and no state is persisted.show()returns false (presenter not available), the coordinator cancels the claim, records no completion, and continues to the next evaluator.show()throws, the claim is cancelled and the surface is not stranded for the rest of the process.Stage transitions
Survey / remote message
markSurveyShownis not called until the survey activity starts.recordLastShownRemoteMessageis not called until the activity starts.UI changes