fix(#1001): make bug-969 hardening tests hermetic + move build tsbuildinfo out of shipped tree (regression from #996) (#1002)

* fix(#969): make bug-969 hardening tests hermetic and move build tsbuildinfo out of shipped tree (regression from #996)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(#969): self-heal legacy bin-local tsbuildinfo and make sentinel test hermetic (adversarial-review follow-ups)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* chore(changeset): set pr number to 1002

* docs(#1001): record DEFECT.SHARED-ARTIFACT-MUTATION-IN-CONCURRENT-TEST anti-pattern in CONTEXT.md

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Tom Boucher
2026-06-10 13:58:56 -04:00
committed by GitHub
parent 88e30d5342
commit adaf3e17d8
8 changed files with 196 additions and 102 deletions

View File

@@ -43,14 +43,15 @@ const SUITES = ['all', 'unit', 'integration', 'install', 'security', 'slow'];
// Common case: fast incremental no-op. Stale/deleted-output case: detected by
// the cheap existsSync loop and force-rebuilt. Paths resolve from __dirname so
// it works regardless of GSD_TEST_DIR / temp-dir cwd.
function ensureBuiltArtifacts() {
function ensureBuiltArtifacts(overrides = {}) {
const { existsSync, readdirSync, statSync, unlinkSync } = require('fs');
const root = join(__dirname, '..');
const srcDir = join(root, 'src');
const outDir = join(root, 'gsd-core', 'bin', 'lib');
const tsBuildInfoPath = join(root, 'gsd-core', 'bin', 'tsconfig.build.tsbuildinfo');
const root = overrides.root || join(__dirname, '..');
const srcDir = overrides.srcDir || join(root, 'src');
const outDir = overrides.outDir || join(root, 'gsd-core', 'bin', 'lib');
const tsBuildInfoPath = overrides.tsBuildInfoPath || join(root, 'tsconfig.build.tsbuildinfo');
const tsconfigPath = overrides.tsconfigPath || join(root, 'tsconfig.build.json');
const tscBin = require.resolve('typescript/bin/tsc');
const tscArgs = [tscBin, '-p', join(root, 'tsconfig.build.json')];
const tscArgs = [tscBin, '-p', tsconfigPath];
// Build the 1:1 map of expected output paths from src/*.cts sources.
// Excludes *.d.cts (declaration-only files that produce no output).
@@ -76,6 +77,13 @@ function ensureBuiltArtifacts() {
return expectedPaths.filter(p => !existsSync(p) || statSync(p).size === 0);
}
// #996 placed the tsbuildinfo inside gsd-core/bin/ (a copied/shipped tree), which
// raced install-test copies. It now lives at the repo root. Best-effort purge any
// stale bin-local copy so persistent workspaces/mirrors self-heal (no-op on a temp
// override root or a clean checkout).
const legacyTsBuildInfo = join(root, 'gsd-core', 'bin', 'tsconfig.build.tsbuildinfo');
try { if (existsSync(legacyTsBuildInfo)) unlinkSync(legacyTsBuildInfo); } catch { /* best-effort */ }
// Step 1: incremental build (fast no-op when sources unchanged).
execFileSync(process.execPath, tscArgs, { cwd: root, stdio: 'inherit' });