From 3e12d8a26accfb98ca0e047d135c3285952eeb78 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 15 Aug 2026 08:08:28 -0700 Subject: [PATCH] test: dedupe coverage gates; route both walks through skill-census MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit skill-coverage-floor duplicated two matrix assertions (registry completeness, gate-tier floor) with a DIFFERENT hand-rolled directory walk — matrix's skipped nothing, floor's skipped node_modules/docs/test. Two 'same' gates disagreeing on the census is the bug class test/helpers/skill-census.ts was written to kill. Registry assertions now live in matrix only (with floor's better error message), both files walk via skillCensus().authoredSkills, and floor keeps the per-skill structural checks it owns. Co-Authored-By: Claude Fable 5 --- test/skill-coverage-floor.test.ts | 45 +++++------------------------- test/skill-coverage-matrix.test.ts | 20 ++++++++----- 2 files changed, 20 insertions(+), 45 deletions(-) diff --git a/test/skill-coverage-floor.test.ts b/test/skill-coverage-floor.test.ts index a0de76292..4f75e370b 100644 --- a/test/skill-coverage-floor.test.ts +++ b/test/skill-coverage-floor.test.ts @@ -19,6 +19,7 @@ import { describe, test, expect } from 'bun:test'; import * as fs from 'fs'; import * as path from 'path'; import { SKILL_COVERAGE } from './skill-coverage-matrix'; +import { skillCensus } from './helpers/skill-census'; const REPO_ROOT = path.resolve(import.meta.dir, '..'); @@ -31,46 +32,14 @@ function readSkillMd(skill: string): string | null { } } -function listSkillDirs(): string[] { - const entries = fs.readdirSync(REPO_ROOT, { withFileTypes: true }); - return entries - .filter(e => e.isDirectory() && !e.name.startsWith('.')) - .filter(e => e.name !== 'node_modules' && e.name !== 'docs' && e.name !== 'test') - .filter(e => fs.existsSync(path.join(REPO_ROOT, e.name, 'SKILL.md'))) - .map(e => e.name) - .sort(); -} +// Registry-completeness assertions ("every skill on disk is registered", +// "every entry has a gate test") live in test/skill-coverage-matrix.test.ts — +// they were duplicated here with a DIFFERENT hand-rolled directory walk, which +// is the divergence class test/helpers/skill-census.ts exists to kill. This +// file owns the per-skill structural compliance checks only. describe('skill-coverage-floor: every skill passes structural compliance', () => { - const skills = listSkillDirs(); - - test('skill registry mentions every skill on disk', () => { - const onDisk = new Set(skills); - const inRegistry = new Set(Object.keys(SKILL_COVERAGE)); - const missingFromRegistry: string[] = []; - for (const s of onDisk) { - if (!inRegistry.has(s)) missingFromRegistry.push(s); - } - if (missingFromRegistry.length > 0) { - throw new Error( - `Skills on disk missing from test/skill-coverage-matrix.ts: ${missingFromRegistry.join(', ')}. ` + - `Add an entry to SKILL_COVERAGE with at least 'test/skill-coverage-floor.test.ts' in gate[].`, - ); - } - }); - - test('every registry entry has at least one gate-tier test', () => { - const missingGate: string[] = []; - for (const [skill, coverage] of Object.entries(SKILL_COVERAGE)) { - if (!coverage.gate || coverage.gate.length === 0) missingGate.push(skill); - } - if (missingGate.length > 0) { - throw new Error( - `Skills with no gate-tier eval: ${missingGate.join(', ')}. ` + - `Eval-first foundation requires at least one CI-blocking check per skill.`, - ); - } - }); + const skills = skillCensus(REPO_ROOT).authoredSkills; test('every gate-tier test path referenced in registry exists on disk', () => { const missing: string[] = []; diff --git a/test/skill-coverage-matrix.test.ts b/test/skill-coverage-matrix.test.ts index 1c212d456..30ec45c18 100644 --- a/test/skill-coverage-matrix.test.ts +++ b/test/skill-coverage-matrix.test.ts @@ -8,18 +8,17 @@ */ import { describe, test, expect } from 'bun:test'; -import * as fs from 'fs'; import * as path from 'path'; import { SKILL_COVERAGE, type SkillCoverage } from './skill-coverage-matrix'; +import { skillCensus } from './helpers/skill-census'; const REPO_ROOT = path.resolve(import.meta.dir, '..'); +// Canonical walk (skill-census.ts). This file and skill-coverage-floor +// previously hand-rolled two DIFFERENT walks (one skipped node_modules/docs/ +// test, one didn't) — exactly the divergence class the census exists to kill. function discoverSkills(): string[] { - return fs.readdirSync(REPO_ROOT, { withFileTypes: true }) - .filter(e => e.isDirectory() && !e.name.startsWith('.')) - .filter(e => fs.existsSync(path.join(REPO_ROOT, e.name, 'SKILL.md'))) - .map(e => e.name) - .sort(); + return skillCensus(REPO_ROOT).authoredSkills; } describe('skill coverage matrix', () => { @@ -29,16 +28,23 @@ describe('skill coverage matrix', () => { }); test('every entry has the right shape', () => { + const missingGate: string[] = []; for (const [skill, coverage] of Object.entries(SKILL_COVERAGE)) { expect(Array.isArray(coverage.gate)).toBe(true); expect(Array.isArray(coverage.periodic)).toBe(true); - expect(coverage.gate.length).toBeGreaterThan(0); + if (!coverage.gate || coverage.gate.length === 0) missingGate.push(skill); for (const p of [...coverage.gate, ...coverage.periodic]) { expect(typeof p).toBe('string'); expect(p.startsWith('test/')).toBe(true); expect(p.endsWith('.test.ts')).toBe(true); } } + if (missingGate.length > 0) { + throw new Error( + `Skills with no gate-tier eval: ${missingGate.join(', ')}. ` + + `Eval-first foundation requires at least one CI-blocking check per skill.`, + ); + } }); test('every skill on disk has a registry entry', () => {