test: move the full office-hours workflow to marathon; add a periodic design-draft checkpoint

The full startup workflow runs 1–3 real spec-review rounds (~280s each) and
hit its 1200s capture in run 36385945043 at finalize. Review depth is the
product's loop, so the case cannot fit a blocking lane without cutting
rounds. It is now marathon tier with every assertion unchanged.

skill-e2e-office-hours-design-draft.test.ts (periodic) runs the same fixed
interview only through the Write that creates the design (269s in that run)
and applies the full validator's design-draft checks, the required section
reads and the launch/foreign-skill-read guards. validateOfficeHoursDesignDraft
is extracted from validateOfficeHoursCompletion, which still applies it.

Selection: office-hours-design-draft is registered periodic; the marathon-only
file is already excluded from the gate and periodic plans by the B5 planner
rule. Tier-alignment regexes and the valid-tier check accept 'marathon'.
A type-only cast in plan-scope-selection.test.ts removes a diagnostic whose
union print order made the ratchet identity unstable; baseline tightened.
This commit is contained in:
garrytan committed 2026-09-29 15:29:46 +00:00
1 parent a41cdb7d7d
commit 4973f96d98
12 files changed
+180 -57

No files matched your search

+25 -11
View File
@@ -3,25 +3,39 @@ import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { DEFAULT_SHARD_TIMEOUT_MS } from '../scripts/test-paid-shards';
import { CAPTURE_LONG_MS } from './helpers/eval-budgets';
const casePath = path.join(import.meta.dir, 'skill-e2e-office-hours-section-loading.test.ts');
// Evaluate the real case registration with inert test/describe functions.
// Imports are removed, and the captured paid callback is never invoked.
function registeredOptions(): { timeout: number; retry: number } {
const source = new Bun.Transpiler({ loader: 'ts' }).transformSync(fs.readFileSync(casePath, 'utf8'))
// Evaluate the real case registrations with inert test/describe functions.
// Imports are removed, and the captured paid callbacks are never invoked.
function registrations(file = casePath): Array<{ tier: string; options: unknown }> {
const source = new Bun.Transpiler({ loader: 'ts' }).transformSync(fs.readFileSync(file, 'utf8'))
.replace(/^import\b[^;]*;\s*$/gm, '');
const registrations: unknown[] = [];
new Function('test', 'describeE2ETier', source)(
(_name: string, _callback: unknown, options: unknown) => registrations.push(options),
() => (_name: string, register: () => void) => register(),
const found: Array<{ tier: string; options: unknown }> = [];
new Function('test', 'describeE2ETier', 'CAPTURE_LONG_MS', source)(
(_name: string, _callback: unknown, options: unknown) => found.at(-1)!.options = options,
(tier: string) => (_name: string, register: () => void) => { found.push({ tier, options: undefined }); register(); },
CAPTURE_LONG_MS,
);
expect(registrations).toHaveLength(1);
return registrations[0] as { timeout: number; retry: number };
return found;
}
test('the full office-hours workflow is one marathon-tier registration', () => {
expect(registrations()).toEqual([{ tier: 'marathon', options: { timeout: 1_260_000, retry: 0 } }]);
});
test('the design-draft checkpoint is one periodic case inside the ordinary long capture budget', () => {
const draft = path.join(import.meta.dir, 'skill-e2e-office-hours-design-draft.test.ts');
expect(registrations(draft)).toEqual([{ tier: 'periodic', options: CAPTURE_LONG_MS }]);
const source = fs.readFileSync(draft, 'utf8');
expect(source).toContain('timeout: LONG_SECTION_CAPTURE_MS');
expect(source).toContain('stop after the Write that saves the complete design');
expect(source).toContain('Do not run the spec review, approval, relationship closing or handoff');
});
test('office-hours has one bounded attempt even under the paid runner CLI retry default', () => {
const options = registeredOptions();
const options = registrations()[0]!.options as { timeout: number; retry: number };
expect(options).toEqual({ timeout: 1_260_000, retry: 0 });
expect(options.timeout + 120_000).toBeLessThanOrEqual(DEFAULT_SHARD_TIMEOUT_MS);