Fold GatesFailed auto-retry into the block subscriber's shared budget
Code review of 1185 (merge 0f4b0c95) found the retry subscriber's central
invariant did not hold: the MergeFailure->Merge bounce caused by its own
retry reset both its attempt counter and the block subscriber's counter,
so the shared merge_failure_block_threshold budget was unreachable and a
deterministic gates failure retried forever.
One subscriber now owns one counter driving both policies:
- Counter survives PipelineEvent::MergeRetryStarted bounces (finding 1);
a third consecutive failure blocks even with retries in between.
- Mixed failure kinds share the single budget (finding 5).
- Retries respect recovery: no counting or scheduling while a mergemaster
is active, and perform_auto_retry re-checks before firing (finding 2).
- perform_auto_retry applies the same eligibility gates as
assign_merge_stage (review hold, frozen, blocked, unmet deps) so freeze
now stops a retry loop (finding 4).
- Per-story scheduling generations invalidate stale sleeping timers
(finding 6).
- One-shot startup scan schedules a catch-up retry for stories already
parked in GatesFailed, so restarts no longer strand them (finding 3);
kept out of the periodic reconciler to avoid re-retrying exhausted
stories every tick.
- Chat is notified only after the merge actually starts; a failed trigger
logs instead of claiming a retry ran (finding 7).
- Config reads moved onto spawn_blocking (finding 8, bug 1170 class).
Deletes merge_failure_retry_subscriber.rs; notification plumbing
(WatcherEvent::MergeAutoRetry et al) is unchanged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019fHdm92yjvguPi2LiXfLB9
This commit is contained in:
@@ -89,24 +89,17 @@ pub(crate) fn spawn_event_bridges(
|
||||
root.clone(),
|
||||
);
|
||||
|
||||
// Consecutive-failure auto-block subscriber: blocks stories after N
|
||||
// consecutive MergeFailure transitions (story 1018). Bug 1025: takes
|
||||
// the agent pool so it can gate the counter on mergemaster presence —
|
||||
// failures during active recovery iteration do not count toward block.
|
||||
// Consecutive-failure budget subscriber: auto-retries GatesFailed
|
||||
// failures below merge_failure_block_threshold (story 1185) and blocks
|
||||
// stories at it (story 1018), with one shared counter. Bug 1025:
|
||||
// takes the agent pool so it can gate both policies on mergemaster
|
||||
// presence — failures during active recovery iteration neither count
|
||||
// nor retry.
|
||||
crate::agents::pool::auto_assign::spawn_merge_failure_block_subscriber(
|
||||
Arc::clone(&agents),
|
||||
root.clone(),
|
||||
);
|
||||
|
||||
// GatesFailed auto-retry subscriber: re-triggers the server-side merge
|
||||
// after a delay for GatesFailed failures, bounded by the same
|
||||
// merge_failure_block_threshold budget the auto-block subscriber above
|
||||
// uses (story 1185).
|
||||
crate::agents::pool::auto_assign::spawn_merge_failure_retry_subscriber(
|
||||
Arc::clone(&agents),
|
||||
root.clone(),
|
||||
);
|
||||
|
||||
// Content-store GC subscriber: purges all ContentKey::* entries for a
|
||||
// story when it reaches a terminal stage, preventing zombie entries from
|
||||
// accumulating in the process heap (story 996).
|
||||
@@ -548,12 +541,11 @@ pub(crate) async fn run_reconcile_pass(
|
||||
// Merge-failure: spawn mergemaster for ConflictDetected stories with no active agent.
|
||||
crate::agents::pool::auto_assign::reconcile_merge_failure(agents, root).await;
|
||||
|
||||
// Merge-block: no-op (in-memory counter cannot be reconstructed from CRDT).
|
||||
// Merge-block: no-op for the periodic pass (in-memory counter cannot be
|
||||
// reconstructed from CRDT); stranded-GatesFailed catch-up runs once at
|
||||
// subscriber startup instead.
|
||||
crate::agents::pool::auto_assign::reconcile_merge_failure_block();
|
||||
|
||||
// Merge-retry: no-op (in-memory attempt counter cannot be reconstructed from CRDT).
|
||||
crate::agents::pool::auto_assign::reconcile_merge_failure_retry();
|
||||
|
||||
// Audit-log: no-op (historical replay would produce misleading entries).
|
||||
crate::pipeline_state::reconcile_audit_log();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user