From 77e57e12db19e45216fe01f387f923c2e2b33982 Mon Sep 17 00:00:00 2001 From: Codex Date: Fri, 3 Jul 2026 06:08:37 +0000 Subject: [PATCH] fix: recognize branch follower closed-out targets --- scripts/src/cicd.ts | 61 ++++++++++++++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/scripts/src/cicd.ts b/scripts/src/cicd.ts index f9212c19..9699158e 100644 --- a/scripts/src/cicd.ts +++ b/scripts/src/cicd.ts @@ -871,24 +871,7 @@ async function readAdapterStatus(follower: FollowerSpec, options: ParsedOptions) "alignment.sourceCommit", ], ["sourceCommit", "observedSha", "observedCommit", "selectedCommit", "selectedSourceCommit"]) ?? adapterObservedShaFromText(result.stdout, follower); - const targetSha = firstStringPath(body, [ - "summary.targetCommit", - "summary.targetSha", - "summary.runtimeCommit", - "summary.gitopsCommit", - "runtime.sourceCommit", - "runtime.commit", - "target.commit", - "target.sha", - "gitops.sourceCommit", - "deployedCommit", - "currentCommit", - "targetSha", - "summary.runtimeAlignment.managerSourceCommit", - "alignment.runtimeAlignment.managerSourceCommit", - "runtime.manager.sourceCommit", - "manager.sourceCommit", - ], ["targetCommit", "targetSha", "runtimeCommit", "gitopsCommit", "deployedCommit", "currentCommit"]); + const targetSha = adapterTargetShaFromStatus(body, result.stdout, follower, observedSha); const lastTriggeredSha = firstStringPath(body, [ "summary.lastTriggeredSha", "summary.lastTriggeredCommit", @@ -960,6 +943,43 @@ function statusMessage(ok: boolean, phase: BranchFollowerPhase, observedSha: str return "status command completed; observed sha not exposed in compact payload"; } +function adapterTargetShaFromStatus(body: Record | null, stdout: string, follower: FollowerSpec, observedSha: string | null): string | null { + const structured = firstStringPath(body, [ + "summary.targetCommit", + "summary.targetSha", + "summary.runtimeCommit", + "summary.gitopsCommit", + "runtime.sourceCommit", + "runtime.commit", + "target.commit", + "target.sha", + "gitops.sourceCommit", + "deployedCommit", + "currentCommit", + "targetSha", + "summary.runtimeAlignment.managerSourceCommit", + "alignment.runtimeAlignment.managerSourceCommit", + "runtime.manager.sourceCommit", + "manager.sourceCommit", + ], ["targetCommit", "targetSha", "runtimeCommit", "gitopsCommit", "deployedCommit", "currentCommit"]); + if (structured !== null) return structured; + if (observedSha !== null && adapterStatusImpliesObservedTarget(body, stdout, follower)) return observedSha; + return null; +} + +function adapterStatusImpliesObservedTarget(body: Record | null, stdout: string, follower: FollowerSpec): boolean { + if (follower.adapter === "hwlab-node-runtime") { + if (booleanAt(body, "ok") === true && booleanAt(body, "summary.ok") !== false) return true; + } + if (follower.adapter === "web-probe-sentinel-cicd") { + if (booleanAt(body, "ok") === true && booleanAt(body, "observed.wait.ready") !== false) return true; + const node = escapeRegex(follower.target.node); + const lane = escapeRegex(follower.target.lane); + if (new RegExp(`\\b${node}\\s+${lane}\\s+ok\\s+status\\b`, "iu").test(stdout)) return true; + } + return false; +} + function mergeFollowerStatus( registry: BranchFollowerRegistry, follower: FollowerSpec, @@ -1338,6 +1358,11 @@ function firstBooleanPath(root: Record | null, paths: string[]) return null; } +function booleanAt(root: Record | null, path: string): boolean | null { + const value = valueAt(root, path); + return typeof value === "boolean" ? value : null; +} + function valueAt(root: unknown, path: string): unknown { let current = root; for (const part of path.split(".")) {