fix(server): NET-6719 mark plan-approval retry runs as safe bootstrap

The reaper's plan-approval continuation retry path runs after the same
CAS write that terminalized the run as process_lost. The shared
scheduleBoundedRetryForRun helper still applies the legacy
legacyExecutionNeedsReconciliation gate, which refuses to schedule a
retry when the failed run lacks explicit bootstrap evidence.

The c8d2b2fd0 fix-forward added that evidence to every reaped run, but
the follow-up 035f4dd79 commit removed it again so monitor-dispatch
losses would still escalate to the board instead of generating spurious
process_lost_retry rows.

Keep both behaviours: only the interaction_continuation_infra_retry
path (which has its own eligibility gates via
isResolvedInteractionContinuationWakeContext and
isRetryableInteractionContinuationInfrastructureFailure) needs the
bootstrap evidence. Add it on the in-memory copy passed to
scheduleBoundedRetryForRun inside
scheduleInteractionContinuationInfrastructureRetryIfEligible so the
shared gate sees safe bootstrap while the persisted row stays
unchanged for the monitor-dispatch / process_lost_retry paths.

NET-6719 / NET-6853
This commit is contained in:
Netquirk Primary Developer 2026-09-12 05:44:30 +00:00
parent d0cf099c5f
commit d90b7f1cb2
1 changed files with 15 additions and 1 deletions

View File

@ -15830,7 +15830,21 @@ export function heartbeatService(
return null; return null;
} }
return scheduleBoundedRetryForRun(run, agent, { // The reaper promoted this run to a process_lost CAS failure before any
// provider work produced output; the retry is an explicit
// infrastructure-loss replay, not an ambiguous bootstrap that the legacy
// reconciliation gate is meant to block. Mark the failed run as safe
// bootstrap evidence on the in-memory copy we hand to
// scheduleBoundedRetryForRun so the shared gate does not refuse the retry.
const runForRetry: typeof run = {
...run,
resultJson: {
...(parseObject(run.resultJson) ?? {}),
executionRecovery: { kind: "bootstrap", providerWorkStarted: false },
},
};
return scheduleBoundedRetryForRun(runForRetry, agent, {
retryReason: INTERACTION_CONTINUATION_INFRA_RETRY_REASON, retryReason: INTERACTION_CONTINUATION_INFRA_RETRY_REASON,
wakeReason: INTERACTION_CONTINUATION_INFRA_WAKE_REASON, wakeReason: INTERACTION_CONTINUATION_INFRA_WAKE_REASON,
maxAttempts: INTERACTION_CONTINUATION_INFRA_MAX_ATTEMPTS, maxAttempts: INTERACTION_CONTINUATION_INFRA_MAX_ATTEMPTS,