From 487d22afb311266f0eaaf6f587505f09c750c10f Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 4 Jul 2026 09:40:06 +0000 Subject: [PATCH] fix: prioritize source discovery before long closeout --- scripts/src/cicd-reconcile-scheduler.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/scripts/src/cicd-reconcile-scheduler.ts b/scripts/src/cicd-reconcile-scheduler.ts index 5ae188f3..4bc69adc 100644 --- a/scripts/src/cicd-reconcile-scheduler.ts +++ b/scripts/src/cicd-reconcile-scheduler.ts @@ -1,9 +1,11 @@ // SPEC: PJ2026-01060703 CI/CD branch follower controller scheduling. -// Responsibility: keep automatic closeout observations ahead of unrelated followers. +// Responsibility: keep source discovery and active closeout ahead of unrelated followers. import type { FollowerSpec, FollowerState, ParsedOptions } from "./cicd-types"; -const CLOSEOUT_PHASES = new Set(["Triggering", "ClosingOut"]); +const ACTIVE_PHASES = new Set(["PendingTrigger", "Triggering", "Superseded"]); +const CLOSEOUT_PHASES = new Set(["ClosingOut"]); +const SOURCE_DISCOVERY_PHASES = new Set(["Observed", "Noop", "Succeeded", "Failed", "Blocked", "Skipped"]); export function orderFollowersForControllerCloseout( followers: FollowerSpec[], @@ -21,14 +23,19 @@ export function shouldYieldAfterAutomaticTrigger(options: ParsedOptions, state: } function followerPriority(state: Record | undefined): number { - if (state === undefined) return 2; + if (state === undefined) return 1; const phase = typeof state.phase === "string" ? state.phase : null; - if (hasStoredSourceTargetMismatch(state)) return 0; - if (hasUnfinishedObservedSource(state)) return 0; - if (phase !== null && CLOSEOUT_PHASES.has(phase)) return 0; if (typeof state.inFlightJob === "string" && state.inFlightJob.trim() !== "") return 0; - if (phase === "PendingTrigger" || phase === "Superseded") return 1; - return 2; + if (phase !== null && ACTIVE_PHASES.has(phase)) return 0; + if (isSourceDiscoveryCandidate(phase)) return 1; + if (hasStoredSourceTargetMismatch(state)) return 2; + if (hasUnfinishedObservedSource(state)) return 2; + if (phase !== null && CLOSEOUT_PHASES.has(phase)) return 2; + return 3; +} + +function isSourceDiscoveryCandidate(phase: string | null): boolean { + return phase === null || SOURCE_DISCOVERY_PHASES.has(phase); } function hasStoredSourceTargetMismatch(state: Record): boolean {