test: delete test-infrastructure dead code (G)

- exit-propagation drives the runner's real strict verdict
  (BunTestOutputClassifier + strictTestExitCode); delete the unused
  shardRunLooksTruncated predicate.
- delete skill-coverage-matrix registry + its gate (nothing reads it; the
  floor already iterates skillCensus()).
- delete touchfiles-facade export-parity tests (Bun fails missing imports
  at link time) and the duplicated E2E_TIERS tier-value test.
- delete brain-cache-spec TRANSPORT_DEFAULT_POLICY, SKILL_RUN_RETENTION_DAYS
  and the now-unused BrainTrustPolicy type with their literal tests.
  AUTOPLAN_PREFLIGHT_BUDGET_BYTES stays: skill-preflight-budget enforces it
  against real resolver output.
- delete audit-compliance's JSDoc-comment grep.
This commit is contained in:
garrytan committed 2026-09-29 04:35:13 +00:00
1 parent 65bfb0ce49
commit 6dc624eda6
10 files changed
+25 -460

No files matched your search

-26
View File
@@ -162,12 +162,6 @@ export const SKILL_CALIBRATION_WEIGHTS: Record<string, number> = {
*/
export const CACHE_REFRESH_LOCK_TIMEOUT_MS = 5 * 60_000;
/**
* Retention policy: gstack/skill-run pages auto-archive after this many days.
* Calibration takes (kind=bet) NEVER archive (long-term scorecard needs them).
*/
export const SKILL_RUN_RETENTION_DAYS = 90;
/**
* Schema pack identity. Bumped when adding/removing/renaming page types.
* On mismatch with the version recorded in _meta.json, the cache layer
@@ -176,26 +170,6 @@ export const SKILL_RUN_RETENTION_DAYS = 90;
export const GSTACK_SCHEMA_PACK_NAME = 'gstack-core';
export const GSTACK_SCHEMA_PACK_VERSION = '1.0.0';
/**
* Trust policy values. Drives auto-push of artifacts, calibration write-back
* eligibility, and user-namespacing strategy.
*/
export type BrainTrustPolicy = 'personal' | 'shared' | 'unset';
/**
* Per-transport default policy. Local engines auto-set to personal (single-tenant
* by construction). Remote endpoints are inferred based on sources_list shape:
* exactly one source + whoami matches → personal default; multiple sources or
* federation → ask the policy question.
*/
export const TRANSPORT_DEFAULT_POLICY: Record<string, BrainTrustPolicy | 'infer'> = {
'local-pglite': 'personal',
'local-stdio': 'personal',
'remote-http-single-tenant': 'personal',
'remote-http-ambiguous': 'unset',
unknown: 'unset',
};
/**
* User-slug fallback chain (D4 A3 defensive default). Resolved once per endpoint
* and persisted via `gstack-config set user_slug_at_<endpoint-hash> <slug>`.
-17
View File
@@ -930,23 +930,6 @@ function formatShardSummary(shards: string[][]): string[] {
});
}
/**
* True when a shard's output shows the run ended WITHOUT bun's final summary
* ("Ran N tests across ..."). A process.exit() fired mid-suite skips the
* summary AND hands back whatever code the caller passed — historically 0,
* which made a truncated shard indistinguishable from a green one. Exit code
* alone is therefore not evidence of completion; the summary line is.
*
* The runner itself now enforces this (and more) through
* scripts/test-strict-output.ts inside runFreeShard; this predicate remains
* the minimal documented primitive that test/exit-propagation.test.ts drives
* with genuine truncated and genuine complete bun runs.
*/
export function shardRunLooksTruncated(status: number | null, output: string): boolean {
if (status !== 0) return false; // already failing — not the silent case
return !/Ran \d+ tests? across \d+ files?/.test(output);
}
// ---------------------------------------------------------------------------
// Output contract: console filtering + per-file failure attribution.
//
-6
View File
@@ -118,12 +118,6 @@ describe('Audit compliance', () => {
});
// Fix 5: Data flow documentation in review.ts
test('review.ts has data flow documentation', () => {
const review = readFileSync(join(ROOT, 'scripts/resolvers/review.ts'), 'utf-8');
expect(review).toContain('Data sent');
expect(review).toContain('Data NOT sent');
});
// Round 2 Fix 3: Extension sender validation + message type allowlist
test('extension background.js validates message sender', () => {
const bg = readFileSync(join(ROOT, 'extension/background.js'), 'utf-8');
-18
View File
@@ -22,12 +22,10 @@ import {
AUTOPLAN_PREFLIGHT_BUDGET_BYTES,
SALIENCE_DEFAULT_ALLOWLIST,
SKILL_CALIBRATION_WEIGHTS,
TRANSPORT_DEFAULT_POLICY,
USER_SLUG_RESOLUTION_ORDER,
GSTACK_SCHEMA_PACK_NAME,
GSTACK_SCHEMA_PACK_VERSION,
CACHE_REFRESH_LOCK_TIMEOUT_MS,
SKILL_RUN_RETENTION_DAYS,
getCacheFile,
getSkillSubset,
getSkillBudget,
@@ -111,18 +109,6 @@ describe('brain-cache-spec internal consistency', () => {
}
});
test('transport policy defaults exist for all transport modes', () => {
const required = ['local-pglite', 'local-stdio', 'remote-http-single-tenant', 'remote-http-ambiguous'];
for (const transport of required) {
expect(TRANSPORT_DEFAULT_POLICY[transport]).toBeDefined();
}
// Local transports must default personal (D4 / Phase 1.5 default rule)
expect(TRANSPORT_DEFAULT_POLICY['local-pglite']).toBe('personal');
expect(TRANSPORT_DEFAULT_POLICY['local-stdio']).toBe('personal');
// Ambiguous remote MUST require explicit ask (never silent default)
expect(TRANSPORT_DEFAULT_POLICY['remote-http-ambiguous']).toBe('unset');
});
test('user-slug resolution chain has 4 deterministic fallbacks ending in non-empty', () => {
expect(USER_SLUG_RESOLUTION_ORDER.length).toBe(4);
expect(USER_SLUG_RESOLUTION_ORDER[USER_SLUG_RESOLUTION_ORDER.length - 1]).toBe('anonymous_hostname_sha8');
@@ -137,10 +123,6 @@ describe('brain-cache-spec internal consistency', () => {
expect(CACHE_REFRESH_LOCK_TIMEOUT_MS).toBe(5 * 60_000);
});
test('skill-run retention is 90 days per D10 lifecycle policy', () => {
expect(SKILL_RUN_RETENTION_DAYS).toBe(90);
});
test('invalidation graph: every "skill-run-write" target also depends on it', () => {
// recent-decisions invalidates on skill-run-write — verify the contract holds
const targets = getInvalidationTargets('skill-run-write');
+19 -14
View File
@@ -3,7 +3,7 @@ import { spawnSync } from 'child_process';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { shardRunLooksTruncated } from '../scripts/test-free-shards';
import { BunTestOutputClassifier, strictTestExitCode } from '../scripts/test-strict-output';
// Fault-injection companion to test/no-suicide-exit.test.ts.
//
@@ -11,9 +11,10 @@ import { shardRunLooksTruncated } from '../scripts/test-free-shards';
// process.exit. This file proves, with real bun output, WHY that guard and
// the sharded runner's summary check both exist: `bun test` itself exits 0
// when a mid-suite process.exit(0) fires — the truncated run is
// indistinguishable from a green one by exit code alone. The sharded
// runner's shardRunLooksTruncated() predicate is the detection layer; these
// tests drive it with genuine truncated and genuine complete runs.
// indistinguishable from a green one by exit code alone. The runner's strict
// verdict (BunTestOutputClassifier + strictTestExitCode, used by runFreeShard)
// is the detection layer; these tests drive it with genuine truncated and
// genuine complete runs.
function runBunTest(dir: string) {
return spawnSync('bun', ['test', '.'], {
@@ -24,6 +25,13 @@ function runBunTest(dir: string) {
});
}
function strictVerdict(r: ReturnType<typeof runBunTest>, expectedFiles: number): number {
const classifier = new BunTestOutputClassifier();
classifier.write(r.stdout ?? '', 'stdout');
classifier.write(r.stderr ?? '', 'stderr');
return strictTestExitCode(r.status ?? 1, classifier.end(), expectedFiles);
}
function withFixtureDir(files: Record<string, string>, fn: (dir: string) => void) {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'exit-prop-'));
try {
@@ -46,16 +54,15 @@ const FAILING_FIXTURE = fs.readFileSync(path.join(FIXTURES, 'failing.txt'), 'utf
const PASSING_FIXTURE = fs.readFileSync(path.join(FIXTURES, 'passing.txt'), 'utf8');
describe('exit-code propagation (fault injection)', () => {
test('a mid-suite process.exit(0) yields exit 0 with NO summary — and the shard predicate catches it', () => {
test('a mid-suite process.exit(0) yields exit 0 with NO summary — and the strict verdict fails it', () => {
withFixtureDir(
{ 'a-suicide.test.ts': SUICIDE_FIXTURE, 'b-failing.test.ts': FAILING_FIXTURE },
(dir) => {
const r = runBunTest(dir);
const combined = `${r.stdout ?? ''}${r.stderr ?? ''}`;
if (r.status === 0) {
// The dangerous shape: green exit, truncated run. The predicate
// MUST flag it — this is the assertion that guards the suite.
expect(shardRunLooksTruncated(r.status, combined)).toBe(true);
// The dangerous shape: green exit, truncated run. The strict
// verdict MUST fail it — this is the assertion that guards the suite.
expect(strictVerdict(r, 2)).not.toBe(0);
} else {
// If a future bun version starts propagating the failure itself,
// even better — nothing to detect. Either way, never green+silent.
@@ -68,18 +75,16 @@ describe('exit-code propagation (fault injection)', () => {
test('a complete green run is NOT flagged as truncated', () => {
withFixtureDir({ 'ok.test.ts': PASSING_FIXTURE }, (dir) => {
const r = runBunTest(dir);
const combined = `${r.stdout ?? ''}${r.stderr ?? ''}`;
expect(r.status).toBe(0);
expect(shardRunLooksTruncated(r.status, combined)).toBe(false);
expect(strictVerdict(r, 1)).toBe(0);
});
});
test('a plain failing run propagates nonzero and is not the silent case', () => {
test('a plain failing run propagates nonzero through the strict verdict', () => {
withFixtureDir({ 'fail.test.ts': FAILING_FIXTURE }, (dir) => {
const r = runBunTest(dir);
const combined = `${r.stdout ?? ''}${r.stderr ?? ''}`;
expect(r.status).not.toBe(0);
expect(shardRunLooksTruncated(r.status, combined)).toBe(false);
expect(strictVerdict(r, 1)).not.toBe(0);
});
});
});
+1 -1
View File
@@ -4,7 +4,7 @@
* Asserts the schema pack is well-formed and matches the v1.48 plan:
* - Exactly 8 page types (7 entities + 1 take)
* - Frontmatter shape is internally consistent
* - Retention policies match SKILL_RUN_RETENTION_DAYS spec
* - Retention policies (skill-run pages archive after 90 days)
* - Link verbs only reference declared verbs
* - JSON payload shape is acceptable to mcp__gbrain__schema_apply_mutations
*
+3 -27
View File
@@ -8,17 +8,14 @@
* frontmatter regressions, missing generated header, empty/trivial bodies,
* and dangling SKILL.md.tmpl-without-SKILL.md mismatches.
*
* Pairs with test/skill-coverage-matrix.ts (the registry) and
* test/parity-suite.test.ts (the content-invariant suite). Together,
* v1.45.0.0 ships with: floor (this file) + matrix (registry CI gate)
* + invariants (content per skill family) + size budget. That's the
* eval-first foundation the v2.0.0.0 sections/ work builds on.
* Pairs with test/parity-suite.test.ts (the content-invariant suite).
* The floor iterates every authored skill from skillCensus(), so a new
* skill is covered without registering it anywhere.
*/
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, '..');
@@ -32,30 +29,9 @@ function readSkillMd(skill: string): string | null {
}
}
// 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 = skillCensus(REPO_ROOT).authoredSkills;
test('every gate-tier test path referenced in registry exists on disk', () => {
const missing: string[] = [];
for (const [skill, coverage] of Object.entries(SKILL_COVERAGE)) {
for (const testPath of [...coverage.gate, ...coverage.periodic]) {
const fullPath = path.join(REPO_ROOT, testPath);
if (!fs.existsSync(fullPath)) {
missing.push(`${skill} → ${testPath}`);
}
}
}
if (missing.length > 0) {
throw new Error(`Registry references missing test files:\n ${missing.join('\n ')}`);
}
});
// Per-skill structural compliance (file IO only, no LLM)
for (const skill of skills) {
describe(`skill: ${skill}`, () => {
-78
View File
@@ -1,78 +0,0 @@
/**
* Skill coverage matrix CI gate (v1.45.0.0 T1).
*
* Asserts every skill on disk has an entry in SKILL_COVERAGE with at
* least one gate-tier test. The detailed per-skill structural checks
* live in test/skill-coverage-floor.test.ts; this file is the matrix-
* level gate that surfaces "skill added but eval not registered" cleanly.
*/
import { describe, test, expect } from 'bun:test';
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 skillCensus(REPO_ROOT).authoredSkills;
}
describe('skill coverage matrix', () => {
test('SKILL_COVERAGE is exported and non-empty', () => {
expect(typeof SKILL_COVERAGE).toBe('object');
expect(Object.keys(SKILL_COVERAGE).length).toBeGreaterThan(0);
});
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);
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', () => {
const skills = discoverSkills();
const missing: string[] = [];
for (const s of skills) {
if (!SKILL_COVERAGE[s]) missing.push(s);
}
if (missing.length > 0) {
throw new Error(
`Skills on disk missing from SKILL_COVERAGE: ${missing.join(', ')}. ` +
`Add an entry to test/skill-coverage-matrix.ts with at least ` +
`'test/skill-coverage-floor.test.ts' in gate[].`,
);
}
});
test('no registry entry references a skill that does not exist on disk', () => {
const skills = new Set(discoverSkills());
const orphans: string[] = [];
for (const skill of Object.keys(SKILL_COVERAGE)) {
if (!skills.has(skill)) orphans.push(skill);
}
if (orphans.length > 0) {
throw new Error(
`Registry references skills not on disk: ${orphans.join(', ')}. ` +
`Remove from SKILL_COVERAGE or restore the skill directory.`,
);
}
});
});
-226
View File
@@ -1,226 +0,0 @@
/**
* Skill coverage matrix (v1.45.0.0 T1, cathedral Phase 0).
*
* Single source of truth mapping each gstack skill to its E2E test files.
* The CI gate at test/skill-coverage-matrix.test.ts fails if a skill has
* no gate-tier entry, ensuring the eval-first foundation holds: every
* skill has at least one CI-blocking check that asserts must-have
* behavior.
*
* Two tiers per entry:
* gate CI-blocking, runs on every PR, target <$0.50/test or free.
* periodic Weekly cron, deeper coverage, can cost ~$1-$3/test.
*
* The 'floor' entry refers to test/skill-coverage-floor.test.ts —
* a structural-compliance smoke test that covers every skill with
* file-IO checks (free, no LLM cost). When a skill has only 'floor'
* coverage, that's the eval-first minimum; future work can layer
* behavioral checks on top.
*/
export interface SkillCoverage {
/** Gate-tier test file paths (relative to repo root). At least one required per skill. */
gate: string[];
/** Periodic-tier test file paths. Optional but recommended. */
periodic: string[];
/** Brief note on why this coverage is the right shape for this skill. */
rationale?: string;
}
/**
* Per-skill coverage. Keys MUST match the top-level skill directory name.
* The CI test asserts every skill in the repo has an entry here AND that
* gate[] is non-empty.
*
* Adding a new skill: add an entry here AND either reference an existing
* test that covers it OR add 'test/skill-coverage-floor.test.ts' as the
* minimum gate-tier check.
*/
export const SKILL_COVERAGE: Record<string, SkillCoverage> = {
// ─── Core loop ──────────────────────────────────────────────
ship: {
gate: ['test/skill-e2e-ship-idempotency.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-workflow.test.ts'],
},
review: {
gate: ['test/skill-e2e-review.test.ts', 'test/skill-e2e-shared-libs.test.ts', 'test/skill-e2e-shared-libs-paths.test.ts', 'test/shared-libs-evidence.test.ts', 'test/shared-libs-rendering.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-review-army.test.ts', 'test/regression-1539-review-self-verify.test.ts'],
},
'deslop-shared-libs': {
gate: ['test/shared-libs-rendering.test.ts', 'test/skill-e2e-shared-libs.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-shared-libs-periodic.test.ts', 'test/codex-e2e-shared-libs.test.ts'],
rationale: 'Free host/discovery checks; native gate traces enforce read-only source access and the actual review advisory lifecycle. Periodic evaluates opportunity and PR coverage judgment.',
},
qa: {
gate: ['test/skill-e2e-qa-workflow.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-qa-workflow.test.ts', 'test/skill-e2e-qa-bugs.test.ts', 'test/skill-e2e-aside.test.ts'],
rationale: 'qa-quick / qa-only-no-fix / qa-bootstrap are gate: the skill drives Aside when it is live and the gstack browse binary otherwise, so CI runs the fallback path. The planted-bug benchmarks, the fix loop and the live-Aside run (aside-qa-quick) are periodic.',
},
'qa-only': {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: [],
rationale: 'qa-only is qa with --report-only; behavior tested via /qa coverage.',
},
investigate: {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: [],
},
browse: {
gate: ['test/skill-e2e-bws.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-aside.test.ts'],
rationale: '/browse drives the Aside browser first (the live E2E aside-browse-basic / aside-browse-flow needs a running Aside, so it is periodic) and the gstack browse binary as fallback (browse-basic / browse-snapshot exercise it, gate; the binary has its own integration suite under browse/test/). Local-HTML rendering (lib/aside-render.ts, bin/gstack-render.ts) is a library, covered by test/aside-render.test.ts.',
},
spec: {
gate: [
'test/spec-template-invariants.test.ts',
'test/spec-template-sync.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: [
'test/skill-e2e-spec-execute.test.ts',
'test/skill-llm-eval-spec.test.ts',
],
rationale: '37 deterministic invariants pin Phase 1/3 gating, --execute race/security hardening, quality-gate redaction, archive contract, plan-mode-aware Phase 5. Periodic adds full PTY pipeline + LLM-judge.',
},
// ─── Plan triad ─────────────────────────────────────────────
'plan-ceo-review': {
gate: [
'test/skill-e2e-plan-ceo-finding-floor.test.ts',
'test/skill-e2e-plan-ceo-plan-mode.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: [
'test/skill-e2e-plan-ceo-finding-count.test.ts',
'test/skill-e2e-plan-ceo-mode-routing.test.ts',
],
},
'plan-eng-review': {
gate: [
'test/shared-libs-rendering.test.ts',
'test/skill-e2e-plan-eng-finding-floor.test.ts',
'test/skill-e2e-plan-eng-plan-mode.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: [
'test/skill-e2e-shared-libs-periodic.test.ts',
'test/skill-e2e-plan-eng-finding-count.test.ts',
'test/skill-e2e-plan-eng-multi-finding-batching.test.ts',
],
},
'plan-design-review': {
gate: [
'test/skill-e2e-plan-design-finding-floor.test.ts',
'test/skill-e2e-plan-design-plan-mode.test.ts',
'test/skill-e2e-plan-design-with-ui.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: ['test/skill-e2e-plan-design-finding-count.test.ts'],
},
'plan-devex-review': {
gate: [
'test/skill-e2e-plan-devex-finding-floor.test.ts',
'test/skill-e2e-plan-devex-plan-mode.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: ['test/skill-e2e-plan-devex-finding-count.test.ts'],
},
autoplan: {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-autoplan-chain.test.ts', 'test/skill-e2e-autoplan-dual-voice.test.ts'],
},
'office-hours': {
gate: ['test/skill-e2e-office-hours.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-office-hours-auto-mode.test.ts', 'test/skill-e2e-office-hours-phase4.test.ts'],
},
// ─── Polish + design ────────────────────────────────────────
'design-review': {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-design.test.ts'],
rationale: 'design-review-fix drives the Aside browser (periodic; skips without one).',
},
'design-consultation': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'design-shotgun': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'design-html': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
diagram: {
gate: ['test/skill-e2e-diagram.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-diagram.test.ts'],
rationale: 'Triplet contract is gate-tier deterministic (gstack-render drives Aside when live, the browse daemon otherwise, so CI runs it); authoring-quality judge is periodic (E2E_TIERS: diagram-triplet/diagram-authoring-quality). The renderer itself is pinned free by test/aside-render.test.ts.',
},
cso: {
gate: ['test/skill-e2e-cso.test.ts', 'test/cso-preserved.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: [],
rationale: 'cso-preserved.test.ts pins must-not-strip security guidance phrases.',
},
'document-release': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'document-generate': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
// ─── Ops + integrations ─────────────────────────────────────
'land-and-deploy': { gate: ['test/skill-e2e-deploy.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
canary: {
gate: ['test/skill-e2e-deploy.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-aside.test.ts'],
rationale: 'canary-workflow (gate) runs the skill in simulation without a browser; aside-canary-quick drives Aside live (periodic).',
},
benchmark: {
gate: ['test/skill-e2e-deploy.test.ts', 'test/skill-e2e-benchmark-providers.test.ts', 'test/skill-coverage-floor.test.ts'],
periodic: [],
rationale: 'benchmark-workflow (gate) runs the skill in simulation without a browser.',
},
'benchmark-models': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
codex: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
retro: {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: ['test/regression-1624-retro-stale-base.test.ts'],
},
'gstack-upgrade': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'context-save': { gate: ['test/skill-e2e-context-skills.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
'context-restore': { gate: ['test/skill-e2e-context-skills.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
'setup-deploy': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'setup-browser-cookies': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'setup-gbrain': {
gate: [
'test/skill-e2e-setup-gbrain-bad-token.test.ts',
'test/skill-e2e-setup-gbrain-path4-local-pglite.test.ts',
'test/skill-e2e-setup-gbrain-remote.test.ts',
'test/skill-coverage-floor.test.ts',
],
periodic: [],
},
'sync-gbrain': {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: ['test/regression-1611-gbrain-sync-resume.test.ts'],
},
'open-gstack-browser': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'pair-agent': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
scrape: {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: ['test/skill-e2e-skillify.test.ts', 'test/skill-e2e-aside.test.ts'],
rationale: '/scrape is Aside-first: aside-scrape-json drives Aside live and checks the JSON-only output discipline (periodic; skips without Aside). scrape-match-path / scrape-prototype-path assert the browser-skills `$B skill list` / `skill run` flow, which the Aside-first template no longer prescribes in its fallback — periodic until the fallback carries it again.',
},
skillify: { gate: ['test/skill-e2e-skillify.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
learn: { gate: ['test/skill-e2e-learnings.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
'plan-tune': { gate: ['test/skill-e2e-plan-tune.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: [] },
// ─── iOS family ─────────────────────────────────────────────
'ios-qa': { gate: ['test/skill-e2e-ios.test.ts', 'test/skill-coverage-floor.test.ts'], periodic: ['test/skill-e2e-ios-device.test.ts', 'test/skill-e2e-ios-swift-build.test.ts'] },
'ios-fix': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'ios-clean': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'ios-sync': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'ios-design-review': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
// ─── Safety / housekeeping ──────────────────────────────────
careful: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
freeze: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
unfreeze: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
guard: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'landing-report': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
health: { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
'make-pdf': {
gate: ['test/skill-coverage-floor.test.ts'],
periodic: [],
rationale: 'make-pdf is a binary with its own free suite under make-pdf/test/ (print pipeline via lib/aside-render.ts); the skill doc is structure-checked by the floor.',
},
'devex-review': { gate: ['test/skill-coverage-floor.test.ts'], periodic: [] },
};
+2 -47
View File
@@ -5,9 +5,8 @@
* (a) touchfiles-data.ts stays LITERALS ONLY — no imports/requires, no call
* expressions, no spreads, no template literals. Map-diff selection
* evaluates old git versions of that file standalone; any logic breaks it.
* (b) the ./helpers/touchfiles facade re-exports EVERY export of both halves
* by identity (===), so existing import sites see the same objects.
* (c) the data file's exports are importable and non-empty.
* (b) the data file's exports are importable and non-empty. A missing facade
* re-export needs no test: Bun fails every importer at link time.
*/
import { describe, test, expect } from 'bun:test';
@@ -15,8 +14,6 @@ import { readFileSync } from 'fs';
import * as path from 'path';
import * as data from './helpers/touchfiles-data';
import * as logic from './helpers/test-selection';
import * as facade from './helpers/touchfiles';
const DATA_PATH = path.join(import.meta.dir, 'helpers', 'touchfiles-data.ts');
@@ -124,40 +121,6 @@ describe('touchfiles-data.ts literal-only tripwire', () => {
});
});
describe('facade export parity', () => {
test('every touchfiles-data export is re-exported by identity', () => {
const dataExports = Object.keys(data);
expect(dataExports.length).toBeGreaterThan(0);
for (const name of dataExports) {
expect(
(facade as Record<string, unknown>)[name],
`facade must re-export '${name}' from touchfiles-data by identity`,
).toBe((data as Record<string, unknown>)[name] as never);
}
});
test('every test-selection export is re-exported by identity', () => {
const logicExports = Object.keys(logic);
expect(logicExports.length).toBeGreaterThan(0);
for (const name of logicExports) {
expect(
(facade as Record<string, unknown>)[name],
`facade must re-export '${name}' from test-selection by identity`,
).toBe((logic as Record<string, unknown>)[name] as never);
}
});
test('facade exports exactly the union of both halves', () => {
const union = new Set([...Object.keys(data), ...Object.keys(logic)]);
expect(new Set(Object.keys(facade))).toEqual(union);
});
test('no export name collisions between data and logic', () => {
const overlap = Object.keys(data).filter((k) => k in logic);
expect(overlap).toEqual([]);
});
});
describe('touchfiles-data exports are importable and non-empty', () => {
test('E2E_TOUCHFILES has entries with non-empty pattern lists', () => {
const keys = Object.keys(data.E2E_TOUCHFILES);
@@ -167,14 +130,6 @@ describe('touchfiles-data exports are importable and non-empty', () => {
}
});
test('E2E_TIERS has entries with valid tier values', () => {
const entries = Object.entries(data.E2E_TIERS);
expect(entries.length).toBeGreaterThan(0);
for (const [key, tier] of entries) {
expect(['gate', 'periodic'], `E2E_TIERS['${key}'] has invalid tier`).toContain(tier);
}
});
test('LLM_JUDGE_TOUCHFILES has entries with non-empty pattern lists', () => {
const keys = Object.keys(data.LLM_JUDGE_TOUCHFILES);
expect(keys.length).toBeGreaterThan(0);