Repository navigation
fix(intents): don't offer lane repair while a lane is resuming - #676
Open
adrianrobinson42 wants to merge 1 commit into
Open
adrianrobinson42 wants to merge 1 commit into
adrianrobinson42 wants to merge 1 commit into
Conversation
Answering a unit-lane question updates only the gate row: the lane's stage stays WAITING_FOR_HUMAN until its runtime resumes, which after a released session can include starting a new instance. The intent page reloads as soon as the answer is saved, finds the stage parked with no pending question, and shows "Parallel execution needs recovery". /repair makes the same check, so pressing Repair stops the run, cancels the resume in flight and discards the answer, and the replayed stage asks the question again. isLaneResumeInFlight (v2-process-keys.js) treats a lane as resuming while the intent is RUNNING or WAITING, its stage is still parked, and the lane's own answered gate had its durable callback delivered (callbackConsumedAt) less than ten minutes ago. The intent detail returns it as stage.laneResuming, judged on the server's clock, and the page shows the lane as resuming instead of offering repair. While any lane is resuming and GetDurableExecution reports the run as live, /repair returns 409 lane_resuming; once the run has ended it can be repaired at once.
adrianrobinson42
requested review from
JWThewes,
eipasteur,
jeromevdl,
leandrodamascena and
svozza
as code owners
November 3, 2026 15:09
This branch has not been deployed
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.
Issue #, if available: Fixes #675
Description of changes:
Problem
When a unit-lane question is answered, the intent page shows Parallel execution needs recovery while the lane is resuming. Repair then stops the run, cancels that resume and discards the answer, and the replayed stage asks the question again. Details and logs are in #675.
Answering a gate updates only the gate row. The stage stays
WAITING_FOR_HUMANuntil its runtime resumes, which after a released session can take a minute. BothderiveLaneWaitsandPOST /repairread "parked with no pending gate" as orphaned. The gate already records that its answer reached the run: the answer route stampscallbackConsumedAtafterSendDurableExecutionCallbackSuccess. Neither check reads it.Solution
Treat a lane whose answer was delivered as resuming, for a bounded time, and judge it on the server:
One rule (
isLaneResumeInFlight,lambda/shared/v2-process-keys.js). A lane counts as resuming when all of these hold:RUNNINGorWAITING;WAITING_FOR_HUMAN;humanTaskMatchesOwner, andpendingHumanTaskIdwhen the stage records it) hascallbackConsumedAt;LANE_RESUME_GRACE_MS(ten minutes) ago.After that the lane is treated as stuck, as before.
Intent detail. Each stage carries
laneResuming, worked out with that rule on the server's clock, so a browser with a slow clock can't hide Repair indefinitely. The detail makes no new AWS calls.Page.
deriveLaneWaitsreturns a newresumingkind for a lane the server reports as resuming. The lane card shows "resuming after the answer", and the recovery banner isn't shown for it. If another lane is stuck at the same time, the banner says Repair is held until the resuming lane restarts, and the button is disabled, because repairing would also stop the resuming lane.POST /repair. While any lane is resuming, it looks up the durable execution (lookupDurableExecutionStatus).409 lane_resumingwith the lanes concerned, and changes nothing.A gate whose callback was never delivered (
resumeAvailable) is unchanged: it still shows as recovery, alongside the existing Resume action.Testing
lambda/intents/test/intents.test.js:/repairreturns409 lane_resumingfor a lane answered 30 s ago on a live run, and stops nothing;GetDurableExecutionreports the run asFAILED;laneResumingonly while the intent isRUNNING.The existing orphaned-lane test, an answered gate with no delivered callback, still repairs.
frontend/src/lib/intentRecovery.test.ts: a lane the server reports as resuming isresuming, notrecovery, and a new pending question still wins.frontend/src/pages/IntentView.test.tsx: no banner or Repair for a lane that is only resuming. With one stuck and one resuming lane, the banner explains the wait and Repair is disabled.On
mainat 3491e29:npm run lintreports no findings in the changed files, andnpm run format:checkpasses.npm --prefix frontend run buildpasses.intentsandsharedvitest projects pass, and so does the pre-commit hook's backend run (61 files, 2,533 tests).bedrock-iam-shell.test.jsfailed once; it passes on rerun with and without this change.The change has been running as a patch in our own deployment, where the problem was found.
Impact
RUNNING, the page can show the lane as resuming until the watchdog marks the intent failed, or for up to ten minutes./repairaccepts a direct call in that window.laneResumingis an added field, so the backend and frontend can be deployed in either order. An older frontend ignores the field, and its Repair button gets the409instead.By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.