From d3ea8dff331ae257034c76d633bbcb2d9ff4b330 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 18 Jun 2026 01:45:18 -0700 Subject: [PATCH] FN-6627: guard dist-barrel tests on complete core dist Align dist-barrel regression guards so partial @fusion/core dist artifacts skip instead of failing mismatched dependency checks. - Add a shared @fusion/test-utils predicate for complete built core dist barrels. - Use the predicate in CLI and core dist-barrel regression tests before importing runtime dist modules. - Cover absent and partial dist directories with focused predicate tests. Files changed: packages/cli/src/__tests__/extension.test.ts | 9 +++-- .../src/__test-utils__/__tests__/core-dist.test.ts | 46 ++++++++++++++++++++++ packages/core/src/__test-utils__/workspace.ts | 11 ++++++ .../core/src/__tests__/task-list-format.test.ts | 17 ++++---- 4 files changed, 72 insertions(+), 11 deletions(-) Fusion-Task-Id: FN-6627 Fusion-Task-Lineage: a05ad009-229d-44c2-a49d-2d9b3f3d6094 --- packages/cli/src/__tests__/extension.test.ts | 9 ++-- .../__tests__/core-dist.test.ts | 46 +++++++++++++++++++ packages/core/src/__test-utils__/workspace.ts | 11 +++++ .../src/__tests__/task-list-format.test.ts | 17 ++++--- 4 files changed, 72 insertions(+), 11 deletions(-) create mode 100644 packages/core/src/__test-utils__/__tests__/core-dist.test.ts diff --git a/packages/cli/src/__tests__/extension.test.ts b/packages/cli/src/__tests__/extension.test.ts index 05d9f478a9..5405e2a929 100644 --- a/packages/cli/src/__tests__/extension.test.ts +++ b/packages/cli/src/__tests__/extension.test.ts @@ -1,5 +1,4 @@ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; -import { existsSync } from "node:fs"; import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises"; import { dirname, join, resolve } from "node:path"; import { tmpdir } from "node:os"; @@ -27,6 +26,7 @@ import kbExtension, { resolveTaskListFormatter } from "../extension.js"; import { TaskStore, AgentStore, MANUAL_RETRY_RESET_COUNTER_KEYS, RESEARCH_RUN_STATUSES, MAX_TASK_LIST_TEXT_CHARS, formatTaskListText } from "@fusion/core"; import type { WorkflowIr } from "@fusion/core"; import { isGhAvailable, isGhAuthenticated, runGhJsonAsync } from "@fusion/core/gh-cli"; +import { hasBuiltCoreDistBarrel } from "@fusion/test-utils"; import { runTaskPlan } from "../commands/task.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -2694,13 +2694,14 @@ describe("fn pi extension (runnable structured-output regression slice)", () => /** * FNXC:TaskListOutput 2026-06-17-02:37: * FN-6535 reproduces the heartbeat failure at the actual CLI tool surface while forcing @fusion/core to resolve through the built dist barrel. The normal CLI suite aliases @fusion/core to source, so this targeted mock is the regression guard for stale exports.import dist artifacts. + * + * FNXC:CoreTests 2026-06-18-01:35: + * FN-6627 aligns the skip gate with every built @fusion/core dist artifact this runtime-dist mock loads, so a partial stale dist skips cleanly while a complete dist still exercises the heartbeat fn_task_list surface. */ - it.skipIf(!existsSync(resolve(__dirname, "../../../core/dist/index.js")))( + it.skipIf(!hasBuiltCoreDistBarrel(resolve(__dirname, "../../../core/dist")))( "executes with @fusion/core resolved through the built dist barrel", async () => { const distCoreIndex = resolve(__dirname, "../../../core/dist/index.js"); - const distTaskListFormat = resolve(__dirname, "../../../core/dist/task-list-format.js"); - expect(existsSync(distTaskListFormat)).toBe(true); const store = new TaskStore(tmpDir); await store.init(); diff --git a/packages/core/src/__test-utils__/__tests__/core-dist.test.ts b/packages/core/src/__test-utils__/__tests__/core-dist.test.ts new file mode 100644 index 0000000000..7339f2c95d --- /dev/null +++ b/packages/core/src/__test-utils__/__tests__/core-dist.test.ts @@ -0,0 +1,46 @@ +import { mkdirSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { hasBuiltCoreDistBarrel, requiredCoreDistFiles, tempWorkspace } from "../workspace.js"; + +describe("hasBuiltCoreDistBarrel", () => { + function makeDistDir() { + const root = tempWorkspace("fusion-core-dist-predicate-"); + const distDir = join(root, "dist"); + mkdirSync(distDir, { recursive: true }); + return distDir; + } + + function touchDistFile(distDir: string, file: (typeof requiredCoreDistFiles)[number]) { + writeFileSync(join(distDir, file), "export {};\n"); + } + + it("returns false when the dist barrel is absent", () => { + const distDir = makeDistDir(); + + expect(hasBuiltCoreDistBarrel(distDir)).toBe(false); + }); + + it("returns false when index.js exists without task-list-format.js", () => { + const distDir = makeDistDir(); + touchDistFile(distDir, "index.js"); + + expect(hasBuiltCoreDistBarrel(distDir)).toBe(false); + }); + + it("returns false when task-list-format.js exists without index.js", () => { + const distDir = makeDistDir(); + touchDistFile(distDir, "task-list-format.js"); + + expect(hasBuiltCoreDistBarrel(distDir)).toBe(false); + }); + + it("returns true only when all required core dist files exist", () => { + const distDir = makeDistDir(); + for (const file of requiredCoreDistFiles) { + touchDistFile(distDir, file); + } + + expect(hasBuiltCoreDistBarrel(distDir)).toBe(true); + }); +}); diff --git a/packages/core/src/__test-utils__/workspace.ts b/packages/core/src/__test-utils__/workspace.ts index 91da16c4a0..e8b7a841a4 100644 --- a/packages/core/src/__test-utils__/workspace.ts +++ b/packages/core/src/__test-utils__/workspace.ts @@ -16,6 +16,17 @@ import { join, resolve } from "node:path"; import { afterEach } from "vitest"; import { assertOutsideRealFusionPath } from "../test-safety.js"; +/** + * FNXC:CoreTests 2026-06-18-01:30: + * FN-6627 requires built-dist-barrel regression guards to skip cleanly when @fusion/core/dist is absent or partial, and to run with full FN-6515/FN-6535 signal only when the same artifacts loaded by the test are present. + * Keep new dist-dependent guards on this predicate instead of checking index.js separately from task-list-format.js body assertions. + */ +export const requiredCoreDistFiles = ["index.js", "task-list-format.js"] as const; + +export function hasBuiltCoreDistBarrel(distDir: string): boolean { + return requiredCoreDistFiles.every((file) => existsSync(resolve(distDir, file))); +} + export function assertOutsideRealFusion(path: string, context = "operation"): void { assertOutsideRealFusionPath(path, context); } diff --git a/packages/core/src/__tests__/task-list-format.test.ts b/packages/core/src/__tests__/task-list-format.test.ts index 2c6a7de7e3..75b4761edd 100644 --- a/packages/core/src/__tests__/task-list-format.test.ts +++ b/packages/core/src/__tests__/task-list-format.test.ts @@ -1,4 +1,3 @@ -import { existsSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import { beforeAll, describe, expect, it } from "vitest"; @@ -7,6 +6,7 @@ import { MAX_TASK_LIST_TEXT_CHARS as SOURCE_BARREL_MAX_TASK_LIST_TEXT_CHARS, formatTaskListText as sourceBarrelFormatTaskListText, } from "../index.js"; +import { hasBuiltCoreDistBarrel } from "@fusion/test-utils"; import { clampTaskListText, formatTaskListText, MAX_TASK_LIST_TEXT_CHARS } from "../task-list-format.js"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -78,18 +78,21 @@ function executeRuntimeTaskList( * FN-6535 requires this guard to execute a fn_task_list-shaped runtime call through the built dist module, not just assert the barrel types. The recurring crash was a post-FN-6492 tool call resolving @fusion/core through exports.import to stale dist, so the regression must fail when that dist omits the helper. */ describe("@fusion/core dist barrel export wiring (FN-6515/FN-6535)", () => { - const distIndex = resolve(__dirname, "../../dist/index.js"); - const distTaskListFormat = resolve(__dirname, "../../dist/task-list-format.js"); + const distDir = resolve(__dirname, "../../dist"); + const hasCompleteDistBarrel = hasBuiltCoreDistBarrel(distDir); + const distIndex = resolve(distDir, "index.js"); let builtDistCore: RuntimeCoreTaskListModule | undefined; /* FNXC:CoreTests 2026-06-17-13:40: FN-6591 requires the FN-6515/FN-6535 dist-barrel guard to settle under broad @fusion/core suite load without timeout, retry, or worker appeasement. Load the built dist barrel once for every dist assertion so heartbeat fn_task_list coverage still exercises the real runtime export path while avoiding duplicate dynamic-import pressure in the timed test bodies. + + FNXC:CoreTests 2026-06-18-01:35: + FN-6627 requires this guard to skip when the built @fusion/core dist barrel is absent or partial, because the runtime import path depends on both index.js and task-list-format.js. */ beforeAll(async () => { - if (!existsSync(distIndex)) return; - expect(existsSync(distTaskListFormat)).toBe(true); + if (!hasCompleteDistBarrel) return; builtDistCore = await import(pathToFileURL(distIndex).href) as RuntimeCoreTaskListModule; }); @@ -99,7 +102,7 @@ describe("@fusion/core dist barrel export wiring (FN-6515/FN-6535)", () => { expect(typeof SOURCE_BARREL_MAX_TASK_LIST_TEXT_CHARS).toBe("number"); }); - it.skipIf(!existsSync(distIndex))("re-exports task-list formatting helpers from the built dist barrel", () => { + it.skipIf(!hasCompleteDistBarrel)("re-exports task-list formatting helpers from the built dist barrel", () => { const mod = builtDistCore; expect(mod).toBeDefined(); @@ -108,7 +111,7 @@ describe("@fusion/core dist barrel export wiring (FN-6515/FN-6535)", () => { expect(typeof mod?.MAX_TASK_LIST_TEXT_CHARS).toBe("number"); }); - it.skipIf(!existsSync(distIndex))("executes the fn_task_list surface through the built dist core module", () => { + it.skipIf(!hasCompleteDistBarrel)("executes the fn_task_list surface through the built dist core module", () => { const mod = builtDistCore as RuntimeCoreTaskListModule; const todoAnchor: RuntimeTask = { id: "FN-001",