diff --git a/scripts/native/cicd/patch-follower-state.mjs b/scripts/native/cicd/patch-follower-state.mjs index 8c60dfa6..68b5e52b 100644 --- a/scripts/native/cicd/patch-follower-state.mjs +++ b/scripts/native/cicd/patch-follower-state.mjs @@ -128,6 +128,70 @@ function preserveExistingTiming(state, existing) { }; } +function recordOrNull(value) { + return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null; +} + +function sameObservedSource(state, existing) { + const incomingCommit = stringOrNull(state?.source?.observedSha) ?? stringOrNull(state?.command?.sourceCommit) ?? stringOrNull(state?.command?.payload?.agentrun?.sourceCommit); + const existingCommit = stringOrNull(existing?.source?.observedSha) ?? stringOrNull(existing?.command?.sourceCommit) ?? stringOrNull(existing?.command?.payload?.agentrun?.sourceCommit); + return incomingCommit !== null && incomingCommit === existingCommit; +} + +function hasAgentRunTriggerEvidence(value) { + const agentrun = recordOrNull(value); + return agentrun !== null && ( + recordOrNull(agentrun.ciConsumption) !== null + || recordOrNull(agentrun.reusePlan) !== null + || recordOrNull(agentrun.imageBuild) !== null + || recordOrNull(agentrun.gitopsPublish) !== null + ); +} + +function preserveAgentRunTriggerEvidence(state, existing) { + if (!sameObservedSource(state, existing)) return state; + const existingAgentrun = recordOrNull(existing?.command?.payload?.agentrun); + if (!hasAgentRunTriggerEvidence(existingAgentrun)) return state; + const command = recordOrNull(state.command); + if (command === null) return state; + const payload = recordOrNull(command.payload); + if (payload === null) return state; + const incomingAgentrun = recordOrNull(payload.agentrun) ?? {}; + const preservedKeys = [ + "configPath", + "sourceCommit", + "reuseConfig", + "reusePlan", + "ciConsumption", + "gitMirrorSync", + "imageBuild", + "gitopsPublish", + "gitMirrorFlush", + ]; + let changed = false; + const mergedAgentrun = { ...incomingAgentrun }; + for (const key of preservedKeys) { + if (mergedAgentrun[key] === undefined || mergedAgentrun[key] === null) { + const existingValue = existingAgentrun[key]; + if (existingValue !== undefined && existingValue !== null) { + mergedAgentrun[key] = existingValue; + changed = true; + } + } + } + if (!changed) return state; + return { + ...state, + command: { + ...command, + payload: { + ...payload, + agentrun: mergedAgentrun, + }, + }, + }; +} + await ensureConfigMap(); const current = await readConfigMap(); const beforeResourceVersion = stringOrNull(current?.metadata?.resourceVersion); @@ -135,7 +199,7 @@ const beforeUpdatedAt = stringOrNull(current?.data?._updatedAt); const currentText = current?.data?.[followerId]; const existing = typeof currentText === "string" && currentText.length > 0 ? JSON.parse(currentText) : null; const incomingState = JSON.parse(stateJson); -const state = preserveExistingTiming(incomingState, existing); +const state = preserveAgentRunTriggerEvidence(preserveExistingTiming(incomingState, existing), existing); const patch = { data: { [followerId]: JSON.stringify(state),