From 12a0b1902d3cbf1751892cebe1f7a33def4d8259 Mon Sep 17 00:00:00 2001 From: JSONbored <49853598+JSONbored@users.noreply.github.com> Date: Thu, 23 Jul 2026 01:44:36 -0700 Subject: [PATCH] fix(ci): grace-window the MCP known-latest audit so same-day releases stop redding every branch Three times in one night (3.4.0, 3.5.0, 3.6.0) a fresh @loopover/mcp publish turned ui:version-audit red for main and every in-flight branch/gate -- a mismatch that is neither the branch's fault nor actionable from it, while the scheduled sync PR (the real fix) lands within minutes anyway. The audit now reads the latest version's publish time from the same registry response: a mismatch within 24h of publish emits a ::warning and passes (the sync PR is the fix); older than that is genuine staleness and still hard-fails -- preserving the #3047 anti-drift discipline. Offline/env-override enforcement (LOOPOVER_MCP_LATEST_VERSION, no publish time available) deliberately stays strict, and --write self-healing is unchanged. --- scripts/check-ui-mcp-version-copy.ts | 40 ++++++++++++++++--- .../check-ui-mcp-version-copy-script.test.ts | 20 ++++++++++ 2 files changed, 55 insertions(+), 5 deletions(-) diff --git a/scripts/check-ui-mcp-version-copy.ts b/scripts/check-ui-mcp-version-copy.ts index 72e5fc6edb..7712611983 100644 --- a/scripts/check-ui-mcp-version-copy.ts +++ b/scripts/check-ui-mcp-version-copy.ts @@ -22,6 +22,23 @@ export const SCAN_TARGETS = [ "apps/loopover-ui/content", ]; +/** How long a freshly-published npm latest may lead the pinned copy before the mismatch hard-fails. + * Rationale (#8179-era fix): on an active release evening the automation publishes several versions and + * files its sync PR within minutes — but every branch/gate in flight goes red on a mismatch that is + * neither the branch's fault nor actionable from it (three same-night cascades on 2026-07-23 alone). + * A mismatch INSIDE the window warns (the sync PR lands the real fix); a mismatch OLDER than the window + * is genuine staleness — the #3047 discipline — and still hard-fails. */ +export const KNOWN_LATEST_GRACE_WINDOW_MS = 24 * 60 * 60 * 1000; + +/** PURE: does a pinned-copy mismatch fail, or merely warn? Fails when the latest's publish time is + * unknown (offline enforcement stays strict) or older than the grace window. */ +export function isMismatchBeyondGrace(publishedAtIso: string | null, nowMs: number): boolean { + if (!publishedAtIso) return true; + const publishedMs = Date.parse(publishedAtIso); + if (!Number.isFinite(publishedMs)) return true; + return nowMs - publishedMs > KNOWN_LATEST_GRACE_WINDOW_MS; +} + export type StaleVersionMatchers = { floorVersion: string; minorLabel: string; @@ -39,10 +56,15 @@ async function main() { // required check one-shot-closes a contributor PR. Set LOOPOVER_MCP_LATEST_VERSION to make it fully // offline/deterministic. The deterministic stale-version-string scan below always runs regardless. let latest = process.env.LOOPOVER_MCP_LATEST_VERSION ?? null; + // Publish time of `latest` (for the grace window below). Stays null under the env override, so offline + // enforcement remains strict — a mismatch there always fails. + let latestPublishedAt: string | null = null; let latestSkipReason = null; if (!latest) { try { - latest = await fetchLatestVersion(); + const release = await fetchLatestRelease(); + latest = release.latest; + latestPublishedAt = release.publishedAt; } catch (error) { latestSkipReason = error instanceof Error ? error.message : "unknown error"; } @@ -59,8 +81,14 @@ async function main() { if (write) { writeKnownLatestVersion(sourceLatestPath, latest); console.log(`${SOURCE_LATEST_PATH}: updated known latest ${sourceLatest} -> ${latest}`); + } else if (isMismatchBeyondGrace(latestPublishedAt, Date.now())) { + failures.push( + `${SOURCE_LATEST_PATH}: known latest ${sourceLatest} does not match npm dist-tags.latest ${latest} (published ${latestPublishedAt ?? "unknown"}, beyond the ${KNOWN_LATEST_GRACE_WINDOW_MS / 3_600_000}h grace window)`, + ); } else { - failures.push(`${SOURCE_LATEST_PATH}: known latest ${sourceLatest} does not match npm dist-tags.latest ${latest}`); + console.warn( + `::warning::${SOURCE_LATEST_PATH}: known latest ${sourceLatest} is behind npm dist-tags.latest ${latest}, published within the grace window -- the scheduled sync PR is the fix; not failing this build`, + ); } } else if (!latest) { console.warn( @@ -177,7 +205,7 @@ export function readMinimumSupportedVersion(path: string): string { return match[1]!; } -export function fetchLatestVersion(): Promise { +export function fetchLatestRelease(): Promise<{ latest: string; publishedAt: string | null }> { return new Promise((resolve, reject) => { const request = get(registryUrl, { headers: { accept: "application/json" } }, (response) => { let body = ""; @@ -191,12 +219,14 @@ export function fetchLatestVersion(): Promise { return; } try { - const latest = JSON.parse(body)?.["dist-tags"]?.latest; + const parsed = JSON.parse(body); + const latest = parsed?.["dist-tags"]?.latest; if (typeof latest !== "string" || !/^\d+\.\d+\.\d+$/.test(latest)) { reject(new Error("npm registry did not return a stable latest version")); return; } - resolve(latest); + const publishedAt = typeof parsed?.time?.[latest] === "string" ? parsed.time[latest] : null; + resolve({ latest, publishedAt }); } catch (error) { reject(error); } diff --git a/test/unit/check-ui-mcp-version-copy-script.test.ts b/test/unit/check-ui-mcp-version-copy-script.test.ts index da45ce47d5..fea0542f65 100644 --- a/test/unit/check-ui-mcp-version-copy-script.test.ts +++ b/test/unit/check-ui-mcp-version-copy-script.test.ts @@ -7,6 +7,8 @@ import { buildStaleVersionMatchers, collectSourceFiles, collectVersionCopyFailures, + isMismatchBeyondGrace, + KNOWN_LATEST_GRACE_WINDOW_MS, isMinimumSupportedContext, isTextSource, readMinimumSupportedVersion, @@ -252,3 +254,21 @@ describe("check-ui-mcp-version-copy script (#6292)", () => { }); }); }); + +describe("isMismatchBeyondGrace (#8179-era release-treadmill fix)", () => { + const NOW = Date.parse("2026-07-23T09:00:00.000Z"); + + it("a mismatch against a freshly-published latest warns (within the grace window)", () => { + expect(isMismatchBeyondGrace(new Date(NOW - 60_000).toISOString(), NOW)).toBe(false); + expect(isMismatchBeyondGrace(new Date(NOW - KNOWN_LATEST_GRACE_WINDOW_MS + 1000).toISOString(), NOW)).toBe(false); + }); + + it("a mismatch older than the grace window is genuine staleness and fails", () => { + expect(isMismatchBeyondGrace(new Date(NOW - KNOWN_LATEST_GRACE_WINDOW_MS - 1000).toISOString(), NOW)).toBe(true); + }); + + it("stays STRICT when the publish time is unknown or garbled — offline/env-override enforcement never softens", () => { + expect(isMismatchBeyondGrace(null, NOW)).toBe(true); + expect(isMismatchBeyondGrace("not-a-time", NOW)).toBe(true); + }); +});