From 389ebe70d8cd999bf1272981bc82081cf3abbea3 Mon Sep 17 00:00:00 2001 From: Gergo Magyar Date: Tue, 9 Jun 2026 13:06:33 +0000 Subject: [PATCH] test(prebuild): hard-gate declared-fully-prebuilt grammars on 6/6 coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The strict 6/6 prebuild assertion was dormant whenever a grammar vendors source (binding.gyp) — which is every grammar — so a dropped prebuild passed CI silently. Add a FULLY_PREBUILT allowlist of grammars GitNexus has committed 6/6 for (today: swift); those must keep all six even with a source fallback, so losing one now fails CI. Grammars graduate into the set as the build-tree-sitter-prebuilds workflow lands their binaries. (The static-import degradation smoke is covered by the registry-import-closure regression test extended in the C lazy-load commit.) --- gitnexus/test/unit/prebuild-coverage.test.ts | 34 ++++++++++++++++---- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/gitnexus/test/unit/prebuild-coverage.test.ts b/gitnexus/test/unit/prebuild-coverage.test.ts index 8ad88a5cd..4765d5abf 100644 --- a/gitnexus/test/unit/prebuild-coverage.test.ts +++ b/gitnexus/test/unit/prebuild-coverage.test.ts @@ -53,6 +53,17 @@ const NODE_MODULES = path.join(GITNEXUS_ROOT, 'node_modules'); */ const KNOWN_NPM_GAPS: Record = {}; +/** + * Vendored grammars declared "fully prebuilt": GitNexus has committed 6/6 + * prebuilds for them, so they MUST keep all six even though they also vendor + * source (binding.gyp). Without this list the strict 6/6 assertion is dormant for + * every grammar that carries source — a dropped prebuild would pass CI silently. + * Grammars graduate into this set as the build-tree-sitter-prebuilds workflow + * lands their binaries (today only Swift ships 6/6; c/dart/proto/kotlin are + * source-build-only until the workflow runs). + */ +const FULLY_PREBUILT = new Set(['tree-sitter-swift']); + function isNapiBinary(file: string): boolean { return readFileSync(file).includes(NAPI_SYMBOL); } @@ -96,21 +107,30 @@ describe('vendored grammar prebuild coverage (toolchain-free on every supported // strict branch below is defensive: a hypothetical prebuild-only grammar (no // binding.gyp) MUST ship all six, or it is dead on the missing platform. const hasSourceFallback = existsSync(path.join(grammarDir, 'binding.gyp')); + // A declared-fully-prebuilt grammar must ship all six EVEN THOUGH it has a + // source fallback — otherwise the strict 6/6 assertion is dormant for every + // source-carrying grammar and a dropped prebuild slips through CI. + const mustBeFullyPrebuilt = FULLY_PREBUILT.has(grammar); it( - hasSourceFallback - ? `${grammar}: present prebuilds are N-API (source-build fallback covers any gaps)` - : `${grammar}: ships an N-API prebuild for all 6 platform-arch tuples`, + mustBeFullyPrebuilt + ? `${grammar}: ships an N-API prebuild for ALL 6 tuples (declared fully-prebuilt)` + : hasSourceFallback + ? `${grammar}: present prebuilds are N-API (source-build fallback covers any gaps)` + : `${grammar}: ships an N-API prebuild for all 6 platform-arch tuples`, () => { // Any prebuild that IS present must be a loadable N-API binary — always. expect(nonNapi, `${grammar} has non-N-API prebuilds: ${nonNapi.join(', ')}`).toEqual([]); - if (!hasSourceFallback) { - // Prebuild-only — run the build-tree-sitter-prebuilds workflow to + if (mustBeFullyPrebuilt || !hasSourceFallback) { + // Either declared fully-prebuilt, or prebuild-only (no source fallback): + // all six are required. Run the build-tree-sitter-prebuilds workflow to // (re)generate any that are missing. expect( missing, - `prebuild-only ${grammar} is missing prebuilds for: ${missing.join(', ') || 'none'} ` + - `(run the build-tree-sitter-prebuilds workflow)`, + `${grammar} is missing prebuilds for: ${missing.join(', ') || 'none'} ` + + (mustBeFullyPrebuilt + ? `(declared fully-prebuilt in FULLY_PREBUILT — its 6/6 set must stay complete)` + : `(prebuild-only — run the build-tree-sitter-prebuilds workflow)`), ).toEqual([]); } },