From c8e6ee530681a329a2d6c8ba3d1551661e7e8545 Mon Sep 17 00:00:00 2001 From: Omar Shahine Date: Sat, 1 Aug 2026 08:32:04 -0700 Subject: [PATCH] fix(ci): invalidate tsgo incremental state whenever boundary dts inputs go stale (#116147) The extension-boundary prep removed .tsbuildinfo only when required outputs were missing. On sticky-disk runners a reused .tsbuildinfo skips re-emitting declarations whose own sources did not change, so cached d.ts files that predate current SDK re-exports survive a stale-input rebuild and fail downstream extension compiles (observed twice on this PR: matrix, then slack, each against exports present in a clean build of the same head). Stale inputs now clear the phase's incremental state before rebuilding. Co-authored-by: Omar Shahine <10343873+omarshahine@users.noreply.github.com> --- ...e-extension-package-boundary-artifacts.mjs | 33 ++++++++----------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/scripts/prepare-extension-package-boundary-artifacts.mjs b/scripts/prepare-extension-package-boundary-artifacts.mjs index c62a1a75597a..a4167a6880bb 100644 --- a/scripts/prepare-extension-package-boundary-artifacts.mjs +++ b/scripts/prepare-extension-package-boundary-artifacts.mjs @@ -416,10 +416,11 @@ function hasMissingOutput(paths) { return paths.some((relativePath) => !fs.existsSync(resolve(repoRoot, relativePath))); } -function removeIncrementalStateForMissingOutput(params) { - if (!hasMissingOutput(params.outputPaths)) { - return; - } +// Stale inputs invalidate the whole incremental emit graph, not just missing +// outputs: reused .tsbuildinfo can skip re-emitting declarations whose own +// sources did not change even when the cached d.ts predates their current +// exports (observed on sticky-disk CI runners). +function removeStaleIncrementalState(params) { fs.rmSync(resolve(repoRoot, params.tsBuildInfoPath), { force: true }); } @@ -802,8 +803,7 @@ async function main(argv = process.argv.slice(2)) { const dependentSteps = []; if (mode === "all") { if (!rootDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: ROOT_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/.tsbuildinfo", }); prerequisiteSteps.push({ @@ -818,8 +818,7 @@ async function main(argv = process.argv.slice(2)) { } } if (!packageDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: PACKAGE_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "packages/plugin-sdk/dist/.tsbuildinfo", }); prerequisiteSteps.push({ @@ -834,8 +833,7 @@ async function main(argv = process.argv.slice(2)) { } if (mode === "all") { if (!qaChannelDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: QA_CHANNEL_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/qa-channel/.tsbuildinfo", }); dependentSteps.push({ @@ -865,8 +863,7 @@ async function main(argv = process.argv.slice(2)) { process.stdout.write("[qa-channel boundary dts] fresh; skipping\n"); } if (!matrixDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: MATRIX_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/matrix/.tsbuildinfo", }); dependentSteps.push({ @@ -896,8 +893,7 @@ async function main(argv = process.argv.slice(2)) { process.stdout.write("[matrix boundary dts] fresh; skipping\n"); } if (!discordDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: DISCORD_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/discord/.tsbuildinfo", }); dependentSteps.push({ @@ -927,8 +923,7 @@ async function main(argv = process.argv.slice(2)) { process.stdout.write("[discord boundary dts] fresh; skipping\n"); } if (!slackDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: SLACK_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/slack/.tsbuildinfo", }); dependentSteps.push({ @@ -958,8 +953,7 @@ async function main(argv = process.argv.slice(2)) { process.stdout.write("[slack boundary dts] fresh; skipping\n"); } if (!whatsappDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: WHATSAPP_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/whatsapp/.tsbuildinfo", }); dependentSteps.push({ @@ -989,8 +983,7 @@ async function main(argv = process.argv.slice(2)) { process.stdout.write("[whatsapp boundary dts] fresh; skipping\n"); } if (!telegramDtsFresh) { - removeIncrementalStateForMissingOutput({ - outputPaths: TELEGRAM_DTS_REQUIRED_OUTPUTS, + removeStaleIncrementalState({ tsBuildInfoPath: "dist/plugin-sdk/extensions/telegram/.tsbuildinfo", }); dependentSteps.push({