mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-03 01:46:55 +02:00
test: skip hollow tier shards and census judges in the paid planner (B5)
A paid file is now skipped for a tier lane only when every E2E id it registers is known statically and none has that tier; ids come from the touchfile registrations and literal testName/*IfSelected arguments, so a comment or skill path that quotes another id cannot unschedule it, and computed names keep today's scheduling. --list and the manifest show each skip as "skipped: no E2E_TIERS id has tier <tier>". The weekly gate census drops the LLM judges (--skip-judges); they still run in the periodic census and PR gate lanes. Gate lane 52 -> 42 files, census 41; periodic 77 -> 69.
This commit is contained in:
1 parent
7cbb5e04e4
commit
799f6ec36c
6 files changed
+108
-10
No files matched your search
@@ -42,7 +42,7 @@ test('the existing quality and behavior phases retain their complete separate sh
|
||||
expect(quality.evalsAll).toBe(true);
|
||||
expect(behavior.evalsAll).toBe(true);
|
||||
expect(qualityFiles).toHaveLength(1);
|
||||
expect(behaviorFiles).toHaveLength(51);
|
||||
expect(behaviorFiles).toHaveLength(41);
|
||||
expect(qualityFiles.every(file => file.startsWith('test/skill-llm-eval'))).toBe(true);
|
||||
expect(behaviorFiles.every(file => !qualityFiles.includes(file))).toBe(true);
|
||||
});
|
||||
|
||||
@@ -124,7 +124,7 @@ test('live periodic census fits the declared CI wall including setup', () => {
|
||||
return paidShardWallUpperBoundMs(files, workers);
|
||||
});
|
||||
expect(Math.max(...walls) + 20 * 60_000).toBeLessThanOrEqual(periodicJob['timeout-minutes'] * 60_000);
|
||||
expect(m.entries.filter(e => e.status === 'planned')).toHaveLength(77);
|
||||
expect(m.entries.filter(e => e.status === 'planned')).toHaveLength(69);
|
||||
const overlays = m.entries.filter(e => e.status === 'planned' && e.slice === periodicSliceCount);
|
||||
expect(overlays).toHaveLength(4);
|
||||
expect(overlays.every(e => isOverlayTestFile(e.file))).toBe(true);
|
||||
@@ -171,7 +171,7 @@ test('current detach supervision covers the live-census floor', () => {
|
||||
const floor = Math.ceil((Math.ceil(files.length / DEFAULT_JOBS) * DEFAULT_SHARD_TIMEOUT_MS + excess) / 1000 * 1.05);
|
||||
const pkg = JSON.parse(fs.readFileSync(path.join(import.meta.dir, '../package.json'), 'utf8'));
|
||||
const configured = Number(pkg.scripts['eval:bg:periodic'].match(/--timeout\s+(\d+)/)[1]);
|
||||
expect(floor).toBe(37800);
|
||||
expect(floor).toBe(35910);
|
||||
expect(configured).toBeGreaterThanOrEqual(floor);
|
||||
expect(pkg.scripts['eval:bg:gate']).toContain('--timeout 36000');
|
||||
});
|
||||
|
||||
@@ -210,9 +210,9 @@ test('both gate executors cover the complete census without increasing aggregate
|
||||
expect(executor.strategy.matrix.slice).toEqual(Array.from({ length: slices }, (_, i) => i + 1));
|
||||
expect(planned.slices).toBe(slices);
|
||||
const manifest = buildRunManifest({ tier: 'gate', sliceCount: planned.slices, evalsAll: true, env: { EVALS_ALL: '1' } });
|
||||
expect(manifest.entries.filter(row => row.status === 'planned')).toHaveLength(52);
|
||||
expect(manifest.entries.filter(row => row.status === 'planned')).toHaveLength(42);
|
||||
const files = manifest.entries.filter(row => row.status === 'planned').map(row => row.file);
|
||||
expect(new Set(files).size).toBe(52);
|
||||
expect(new Set(files).size).toBe(42);
|
||||
expect(files.sort()).toEqual(selectPaidTestFiles(collectPaidTestFiles(), 'gate').selected.sort());
|
||||
const walls = executor.strategy.matrix.slice.map((slice: number) => paidShardWallUpperBoundMs(
|
||||
manifest.entries.filter(row => row.status === 'planned' && row.slice === slice).map(row => row.file), workers,
|
||||
@@ -246,7 +246,7 @@ test('the periodic executor supervises every actual case and retry within its CI
|
||||
const manifest = buildRunManifest({ tier: 'periodic', sliceCount: planned.slices,
|
||||
evalsAll: true, env: { EVALS_ALL: '1' } });
|
||||
const census = manifest.entries.filter(row => row.status === 'planned');
|
||||
expect(census).toHaveLength(77);
|
||||
expect(census).toHaveLength(69);
|
||||
expect(census.find(row => row.file === 'test/skill-llm-eval.test.ts')?.budget?.timeoutMs).toBe(5_960_000);
|
||||
const walls = executor.strategy.matrix.slice.map((slice: number) => paidShardWallUpperBoundMs(
|
||||
census.filter(row => row.slice === slice).map(row => row.file), active.jobs,
|
||||
|
||||
@@ -30,6 +30,8 @@ import {
|
||||
runPaidShards,
|
||||
summarize,
|
||||
summaryExitCode,
|
||||
tierSkipReason,
|
||||
buildRunManifest,
|
||||
type ShardOutcome,
|
||||
} from '../scripts/test-paid-shards';
|
||||
|
||||
@@ -68,6 +70,57 @@ describe('paid test enumeration', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('tier lane skip (B5)', () => {
|
||||
const file = 'test/skill-e2e-sample.test.ts';
|
||||
const touchfiles = { 'sample-gate': [file, 'sample/**'], 'sample-periodic': [file], other: ['x/**'] };
|
||||
const tiers = { 'sample-gate': 'gate', 'sample-periodic': 'periodic', other: 'periodic' };
|
||||
const reg = { 'sample-gate': [file] } as Record<string, string[]>;
|
||||
|
||||
test('a fully static file with only other-tier ids is skipped with its reason', () => {
|
||||
const source = "describeIfSelected('Sample', ['sample-gate'], () => { testIfSelected('sample-gate', async () => {}); });";
|
||||
expect(tierSkipReason(file, source, 'periodic', reg, tiers)).toBe('skipped: no E2E_TIERS id has tier periodic');
|
||||
expect(tierSkipReason(file, source, 'gate', reg, tiers)).toBeNull();
|
||||
});
|
||||
|
||||
test('a comment or path that quotes another-tier id cannot change the decision', () => {
|
||||
const source = "// see 'other' and 'sample-periodic' for context\nconst dir = 'sample-periodic/fixtures';\n" +
|
||||
"testIfSelected('sample-gate', async () => {});";
|
||||
expect(tierSkipReason(file, source, 'periodic', reg, tiers)).toBe('skipped: no E2E_TIERS id has tier periodic');
|
||||
expect(tierSkipReason(file, source, 'gate', reg, tiers)).toBeNull();
|
||||
});
|
||||
|
||||
test('computed registrations, unregistered literal ids and id-less files keep today\'s scheduling', () => {
|
||||
for (const source of [
|
||||
"describeIfSelected(name, keys, () => {});",
|
||||
"describeIfSelected('Sample', [...keys], () => {});",
|
||||
"testConcurrentIfSelected(`sample-${label}`, async () => {});",
|
||||
"runSkillTest({ testName: `sample-${label}` });",
|
||||
"testIfSelected(caseName, async () => {});",
|
||||
]) expect(tierSkipReason(file, source, 'periodic', reg, tiers)).toBeNull();
|
||||
expect(tierSkipReason(file, "testIfSelected('sample-periodic', async () => {});", 'periodic', reg, tiers)).toBeNull();
|
||||
expect(tierSkipReason(file, "testIfSelected('sample-gate', async () => {});", 'periodic', {}, tiers)).toBeNull();
|
||||
expect(tierSkipReason(file, "testIfSelected('sample-gate', async () => {});", 'gate', touchfiles, tiers)).toBeNull();
|
||||
});
|
||||
|
||||
test('the real constructed-name diagram file stays scheduled in both lanes', () => {
|
||||
const source = fs.readFileSync(path.join(ROOT, 'test/skill-e2e-diagram.test.ts'), 'utf8');
|
||||
for (const tier of ['gate', 'periodic'] as const) expect(tierSkipReason('test/skill-e2e-diagram.test.ts', source, tier)).toBeNull();
|
||||
});
|
||||
|
||||
test('the weekly gate census alone drops the LLM judges, with the reason in the manifest', () => {
|
||||
const census = buildRunManifest({ tier: 'gate', sliceCount: 7, evalsAll: true, skipJudges: true, env: { EVALS_ALL: '1' } });
|
||||
const judge = census.entries.find(entry => entry.file === 'test/skill-llm-eval.test.ts');
|
||||
expect(judge).toMatchObject({ status: 'excluded', reason: 'skipped: LLM judges run in the periodic census and PR gate lanes' });
|
||||
for (const tier of ['gate', 'periodic'] as const) {
|
||||
const lane = buildRunManifest({ tier, sliceCount: 7, evalsAll: true, env: { EVALS_ALL: '1' } });
|
||||
expect(lane.entries.find(entry => entry.file === 'test/skill-llm-eval.test.ts')?.status).toBe('planned');
|
||||
}
|
||||
const workflow = fs.readFileSync(path.join(ROOT, '.github/workflows/evals-periodic.yml'), 'utf8');
|
||||
expect(workflow.match(/--skip-judges/g)).toHaveLength(1);
|
||||
expect(workflow).toMatch(/--tier gate --emit-plan \/tmp\/gate-census-plan\/manifest\.json --slices 7 --skip-judges/);
|
||||
});
|
||||
});
|
||||
|
||||
describe('tier classification', () => {
|
||||
test('excludes only on an explicit other-tier guard', () => {
|
||||
const gateGuard = "const shouldRun = !!process.env.EVALS && process.env.EVALS_TIER === 'gate';";
|
||||
|
||||
Reference in new issue
Block a user