Merge origin/main (v1.64.1.0 code-smell wave) into test-evals-ci-speedup

Both sides shipped overlapping test-infra work in parallel; resolutions
compose intent rather than picking sides:

- free-tests.yml (both added): keep this branch's lane (canonical
  strict-parallel runner, secretless, plain runner, ~2min) over main's
  per-file-serial container loop (45min budget, hand-curated skip list,
  needs GITHUB_TOKEN); ported main's git safe.directory insight.
- Dockerfile.ci Bun install: main discovered the installer IGNORES the
  BUN_VERSION env var (the old form silently installed latest) — main's
  arg-form mechanism + this branch's 1.3.13 target.
- parity baseline: both sides rebased after hitting the same silent
  drift; adopted main's v1.64.1.0 union-normalized fixture and dropped
  this branch's interim v1.64.0.0 capture. carve-guards caps: main's
  tighter re-ratchets win (all four).
- touchfiles: kept this branch's three-file facade split; ported main's
  pure-data removals (dead sidebar-agent entries, spec judge entry,
  ship-idempotency) into touchfiles-data.ts.
- ship-idempotency SDK variant: main deliberately removed it as
  redundant with the real-PTY test; adopted — dropped this branch's
  rehomed copy and its periodic matrix row (the zombie-monolith deletion
  stands; coverage-audit + triage rehomes verified untouched by main).
- e2e-tier-alignment: taught the new parent-mapper hard check main's
  consolidated describeE2ETier()/e2eTierEnabled() self-gate shapes (the
  helper's header names this file as a required recognizer).
- browse/test/compare-board.test.ts: quarantined behind
  GSTACK_COMPARE_BOARD_TESTS=1 — all 16 tests fail identically on
  origin/main solo on dev machines (blame protocol receipts in-file);
  main's own CI lane skip-lists it. An always-red file would block every
  PR now that free-tests is a required check.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-15 10:29:25 -07:00
co-authored by Claude Fable 5
192 changed files with 2371 additions and 22872 deletions
+8
View File
@@ -22,6 +22,14 @@ import { execSync } from 'child_process';
export interface SkillBaselineEntry {
skill: string;
/**
* SKILL.md file bytes as captured. NOTE for rebaselines: the parity harness
* compares UNION bytes (skeleton + sections/*.md) against this field, so a
* committed baseline fixture must have carved skills' entries normalized to
* union size (skeleton + sum of sections/*.md) or every carved skill reads
* as 1.2-1.4x over on day one. The v1.57.7.0 and v1.64.1.0 fixtures are
* union-normalized.
*/
skillMdBytes: number;
skillMdLines: number;
estTokens: number; // ~4 chars/token heuristic
+11 -11
View File
@@ -144,9 +144,9 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
},
behavioral: 'external',
externalTest: 'test/skill-e2e-plan-ceo-review-section-loading.test.ts',
// Re-ratcheted 2026-08 (v1.64 baseline rebase): v1.58-v1.64 growth landed
// while no CI lane ran the parity check; free-tests lane now enforces it.
maxSkeletonBytes: 92_000,
// v1.64.1.0: shared-preamble prose from the two parallel v1.64 waves lands
// the skeleton at 90,280 B; +1 KB headroom.
maxSkeletonBytes: 91_000,
minUnionBytes: 80_000,
mustContain: ['SCOPE EXPANSION', 'SELECTIVE EXPANSION', 'HOLD SCOPE', 'SCOPE REDUCTION'],
// Default-on Codex outside-voice (codexPreflight block + CODEX_MODE branch
@@ -167,9 +167,9 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
behavioral: 'plan',
// v1.2.0 activation lift (shared first-run-guidance preamble) + #2077 ask-first scope gate.
// +~1 KB: plan-mode auto-select-B scope-gate exceptions (2026-08).
// Re-ratcheted 2026-08 (v1.64 baseline rebase): v1.58-v1.64 growth landed
// while no CI lane ran the parity check; free-tests lane now enforces it.
maxSkeletonBytes: 70_000,
// v1.64.1.0: shared-preamble prose from the two parallel v1.64 waves lands
// the skeleton at 68,163 B; +~1 KB headroom.
maxSkeletonBytes: 69_000,
minUnionBytes: 70_000,
mustContain: ['Architecture', 'Code Quality', 'Test', 'Performance'],
// Cross-cutting preamble growth (v1.57.2.0 AUQ-failure prose fallback + the
@@ -244,9 +244,9 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
behavioral: 'prompt',
// v1.2.0 activation lift: first-run-guidance section in the shared preamble,
// plus the P1 office-hours closing handoff (AUQ that launches the next skill).
// Re-ratcheted 2026-08 (v1.64 baseline rebase): v1.58-v1.64 growth landed
// while no CI lane ran the parity check; free-tests lane now enforces it.
maxSkeletonBytes: 100_000,
// v1.64.1.0: shared-preamble prose from the two parallel v1.64 waves lands
// the skeleton at 98,193 B; +~1 KB headroom.
maxSkeletonBytes: 99_000,
minUnionBytes: 70_000,
mustContain: ['design doc', 'problem statement'],
maxSizeRatio: 1.07,
@@ -295,8 +295,8 @@ export const CARVE_GUARDS: Record<string, CarveGuard> = {
// +Conductor AUQ-default-prose rule + one-way/continuation safety in the
// always-loaded AskUserQuestion Format section.
// v1.2.0 activation lift: first-run-guidance section in the shared preamble.
// Re-ratcheted 2026-08 (v1.64 baseline rebase): v1.58-v1.64 growth landed
// while no CI lane ran the parity check; free-tests lane now enforces it.
// v1.64.1.0: shared-preamble prose from the two parallel v1.64 waves lands
// the skeleton at 69,022 B; +~1 KB headroom.
maxSkeletonBytes: 70_000,
minUnionBytes: 72_000,
mustContain: ['Typography', 'Color', 'Aesthetic Direction'],
+4 -1
View File
@@ -454,8 +454,11 @@ ${tail}
};
try {
// Use the same binary resolution as every PTY launch in this file —
// judgePtyState previously hardcoded bare 'claude' three definitions
// below resolveClaudeBinary(), breaking under hermetic PATHs.
const result = nodeSpawnSync(
'claude',
resolveClaudeBinary() ?? 'claude',
['-p', '--model', 'claude-haiku-4-5', '--max-turns', '1'],
{
input: prompt,
+51
View File
@@ -0,0 +1,51 @@
/**
* Whole-file E2E tier gate — the single definition of the
* `EVALS=1 && EVALS_TIER === '<tier>'` predicate that tier-gated paid test
* files used to copy-paste (~36 local copies before consolidation).
*
* This module MUST stay side-effect-free. It is imported at module scope by
* every tier-gated test file, including files the sharded paid runner
* (scripts/test-paid-shards.ts) spawns one-process-each — unlike
* test/helpers/e2e-helpers.ts, whose EVALS=1 module-scope work includes a
* ~30s `claude -p` connectivity ping, diff-based selection, and ~/.gstack
* pre-seeding. The only import allowed here is `bun:test`.
* test/helpers/e2e-gate.unit.test.ts enforces this with a source scan.
*
* Env is read at CALL time (the importing test file's module top-level), not
* captured at this module's load time, so the gate behaves identically under
* single-process `bun test` globs and the sharded runner's per-shard env.
*
* Static-grep consumers that must recognize the call shape
* `describeE2ETier('<tier>')` / `e2eTierEnabled('<tier>')` alongside the raw
* `EVALS_TIER === '<tier>'` predicate:
* - test/e2e-tier-alignment.test.ts (HELPER_GATE_RE) — tier-alignment invariant
* - scripts/test-paid-shards.ts classifyPaidTestFile — pre-spawn tier exclusion
*/
import { describe } from 'bun:test';
export type E2ETier = 'gate' | 'periodic';
/**
* True when this process should run whole-file-gated paid tests of `tier`:
* EVALS=1 AND EVALS_TIER exactly equals the tier.
*
* Deliberate consequence: EVALS=1 with EVALS_TIER unset is false for BOTH
* tiers. Tierless runs (`test:evals` / `eval:bg` / `eval:bg:all`) skip every
* tier-gated file and rely on diff-based per-test selection instead — that is
* the long-standing behavior of the copy-pasted predicates, pinned by
* test/helpers/e2e-gate.unit.test.ts.
*/
export function e2eTierEnabled(tier: E2ETier): boolean {
return !!process.env.EVALS && process.env.EVALS_TIER === tier;
}
/**
* `describe` when `e2eTierEnabled(tier)`, else `describe.skip`.
*
* Usage (module top-level of a tier-gated test file):
* const describeE2E = describeE2ETier('periodic');
*/
export function describeE2ETier(tier: E2ETier): typeof describe | typeof describe.skip {
return e2eTierEnabled(tier) ? describe : describe.skip;
}
+103
View File
@@ -0,0 +1,103 @@
/**
* Pins the consolidated E2E tier gate (test/helpers/e2e-gate.ts).
*
* Two invariants:
* 1. The env matrix — including the tierless-run trap: EVALS=1 with
* EVALS_TIER unset must SKIP both tiers (that is how `test:evals` /
* `eval:bg:all` have always treated whole-file tier gates; per-test
* diff selection covers those runs instead).
* 2. Module purity — e2e-gate.ts is imported at module scope by every
* tier-gated paid test file, one-process-each under the sharded
* runner. Its only import must be `bun:test` and it must contain no
* spawn/network/fs machinery (the reason it cannot live in
* e2e-helpers.ts, whose EVALS=1 module scope runs a ~30s claude ping).
*/
import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
import * as fs from 'fs';
import * as path from 'path';
import { describeE2ETier, e2eTierEnabled } from './e2e-gate';
const SAVED_EVALS = process.env.EVALS;
const SAVED_TIER = process.env.EVALS_TIER;
function restoreEnv() {
if (SAVED_EVALS === undefined) delete process.env.EVALS;
else process.env.EVALS = SAVED_EVALS;
if (SAVED_TIER === undefined) delete process.env.EVALS_TIER;
else process.env.EVALS_TIER = SAVED_TIER;
}
describe('e2e-gate: env matrix (read at call time)', () => {
beforeEach(() => {
delete process.env.EVALS;
delete process.env.EVALS_TIER;
});
afterEach(restoreEnv);
test('EVALS unset → skip, even when EVALS_TIER matches', () => {
process.env.EVALS_TIER = 'gate';
expect(e2eTierEnabled('gate')).toBe(false);
expect(describeE2ETier('gate')).toBe(describe.skip);
expect(describeE2ETier('periodic')).toBe(describe.skip);
});
test('EVALS=1 + matching tier → run', () => {
process.env.EVALS = '1';
process.env.EVALS_TIER = 'gate';
expect(e2eTierEnabled('gate')).toBe(true);
expect(describeE2ETier('gate')).toBe(describe);
process.env.EVALS_TIER = 'periodic';
expect(e2eTierEnabled('periodic')).toBe(true);
expect(describeE2ETier('periodic')).toBe(describe);
});
test('EVALS=1 + other tier → skip', () => {
process.env.EVALS = '1';
process.env.EVALS_TIER = 'periodic';
expect(e2eTierEnabled('gate')).toBe(false);
expect(describeE2ETier('gate')).toBe(describe.skip);
process.env.EVALS_TIER = 'gate';
expect(e2eTierEnabled('periodic')).toBe(false);
expect(describeE2ETier('periodic')).toBe(describe.skip);
});
test('EVALS=1 + EVALS_TIER unset → skip both tiers (the tierless test:evals / eval:bg:all trap)', () => {
process.env.EVALS = '1';
expect(e2eTierEnabled('gate')).toBe(false);
expect(e2eTierEnabled('periodic')).toBe(false);
expect(describeE2ETier('gate')).toBe(describe.skip);
expect(describeE2ETier('periodic')).toBe(describe.skip);
});
});
describe('e2e-gate: module purity (side-effect-free import)', () => {
const source = fs.readFileSync(path.join(import.meta.dir, 'e2e-gate.ts'), 'utf-8');
test('the only import specifier is bun:test', () => {
const specifiers = [...source.matchAll(/from\s+['"]([^'"]+)['"]/g)].map((m) => m[1]);
expect(specifiers.length).toBeGreaterThan(0);
expect(specifiers.filter((s) => s !== 'bun:test')).toEqual([]);
// No dynamic escape hatches either.
expect(source).not.toMatch(/\brequire\s*\(/);
expect(source).not.toMatch(/\bimport\s*\(/);
});
test('no spawn / network / fs machinery in the module body', () => {
// Strip comments so prose explaining WHY the module must stay pure
// (which legitimately names spawnSync etc.) doesn't trip the scan.
const code = source
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\/\/[^\n]*/g, '');
for (const banned of [
'spawnSync', 'spawn(', 'execSync', 'child_process',
'Bun.spawn', 'Bun.file', 'Bun.write',
'fetch(', 'WebSocket', 'XMLHttpRequest',
'readFileSync', 'writeFileSync', 'mkdirSync', 'node:fs', "from 'fs'",
]) {
expect(code.includes(banned), `e2e-gate.ts must not contain "${banned}"`).toBe(false);
}
});
});
+33 -18
View File
@@ -33,26 +33,36 @@ export const evalsEnabled = !!process.env.EVALS;
// --- Diff-based test selection ---
// When EVALS_ALL is not set, only run tests whose touchfiles were modified.
// Set EVALS_ALL=1 to force all tests. Set EVALS_BASE to override base branch.
export let selectedTests: string[] | null = null; // null = run all
if (evalsEnabled && !process.env.EVALS_ALL) {
/**
* Compute the diff-based selection for a touchfiles table. Returns null for
* "run all" (EVALS off, EVALS_ALL=1, or no diff vs the base branch — e.g. on
* main). Shared by this module (E2E_TOUCHFILES) and skill-llm-eval.test.ts
* (LLM_JUDGE_TOUCHFILES) so the selection logic exists exactly once.
*/
export function computeDiffSelection(
touchfiles: Record<string, string[]>,
label: string,
): string[] | null {
if (!evalsEnabled || process.env.EVALS_ALL) return null;
const baseBranch = process.env.EVALS_BASE
|| detectBaseBranch(ROOT)
|| 'main';
const changedFiles = getChangedFiles(baseBranch, ROOT);
// If changedFiles is empty (e.g., on main branch), run all
if (changedFiles.length === 0) return null;
if (changedFiles.length > 0) {
const selection = selectTests(changedFiles, E2E_TOUCHFILES, GLOBAL_TOUCHFILES);
selectedTests = selection.selected;
process.stderr.write(`\nE2E selection (${selection.reason}): ${selection.selected.length}/${Object.keys(E2E_TOUCHFILES).length} tests\n`);
if (selection.skipped.length > 0) {
process.stderr.write(` Skipped: ${selection.skipped.join(', ')}\n`);
}
process.stderr.write('\n');
const selection = selectTests(changedFiles, touchfiles, GLOBAL_TOUCHFILES);
process.stderr.write(`\n${label} selection (${selection.reason}): ${selection.selected.length}/${Object.keys(touchfiles).length} tests\n`);
if (selection.skipped.length > 0) {
process.stderr.write(` Skipped: ${selection.skipped.join(', ')}\n`);
}
// If changedFiles is empty (e.g., on main branch), selectedTests stays null → run all
process.stderr.write('\n');
return selection.selected;
}
export let selectedTests: string[] | null = computeDiffSelection(E2E_TOUCHFILES, 'E2E'); // null = run all
// EVALS_TIER: filter tests by tier after diff-based selection.
// 'gate' = gate tests only (CI default — blocks merge)
// 'periodic' = periodic tests only (weekly cron / manual)
@@ -73,9 +83,14 @@ if (evalsEnabled && process.env.EVALS_TIER) {
export const describeE2E = evalsEnabled ? describe : describe.skip;
/** Wrap a describe block to skip entirely if none of its tests are selected. */
export function describeIfSelected(name: string, testNames: string[], fn: () => void) {
const anySelected = selectedTests === null || testNames.some(t => selectedTests!.includes(t));
/**
* Wrap a describe block to skip entirely if none of its tests are selected.
* `selected` defaults to this module's E2E selection (diff + EVALS_TIER);
* pass an explicit selection (e.g. computeDiffSelection over
* LLM_JUDGE_TOUCHFILES) to reuse the gating against a different table.
*/
export function describeIfSelected(name: string, testNames: string[], fn: () => void, selected: string[] | null = selectedTests) {
const anySelected = selected === null || testNames.some(t => selected.includes(t));
(anySelected ? describeE2E : describe.skip)(name, fn);
}
@@ -270,14 +285,14 @@ if (evalsEnabled) {
}
/** Skip an individual test if not selected (for multi-test describe blocks). */
export function testIfSelected(testName: string, fn: () => Promise<void>, timeout: number) {
const shouldRun = selectedTests === null || selectedTests.includes(testName);
export function testIfSelected(testName: string, fn: () => Promise<void>, timeout: number, selected: string[] | null = selectedTests) {
const shouldRun = selected === null || selected.includes(testName);
(shouldRun ? test : test.skip)(testName, fn, timeout);
}
/** Concurrent version — runs in parallel with other concurrent tests within the same describe block. */
export function testConcurrentIfSelected(testName: string, fn: () => Promise<void>, timeout: number) {
const shouldRun = selectedTests === null || selectedTests.includes(testName);
export function testConcurrentIfSelected(testName: string, fn: () => Promise<void>, timeout: number, selected: string[] | null = selectedTests) {
const shouldRun = selected === null || selected.includes(testName);
(shouldRun ? test.concurrent : test.skip)(testName, fn, timeout);
}
-11
View File
@@ -284,7 +284,6 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
// Plan completion audit + verification
'ship-plan-completion': ['ship/**', 'scripts/gen-skill-docs.ts'],
'ship-plan-verification': ['ship/**', 'qa-only/**', 'scripts/gen-skill-docs.ts'],
'ship-idempotency': ['ship/**', 'scripts/resolvers/utility.ts'],
'review-plan-completion': ['review/**', 'scripts/gen-skill-docs.ts'],
// Design
@@ -316,10 +315,6 @@ export const E2E_TOUCHFILES: Record<string, string[]> = {
'benchmark-workflow': ['benchmark/**', 'browse/src/**'],
'setup-deploy-workflow': ['setup-deploy/**', 'scripts/gen-skill-docs.ts'],
// Sidebar agent
'sidebar-navigate': ['browse/src/server.ts', 'browse/src/sidebar-agent.ts', 'browse/src/sidebar-utils.ts', 'extension/**'],
'sidebar-url-accuracy': ['browse/src/server.ts', 'browse/src/sidebar-agent.ts', 'browse/src/sidebar-utils.ts', 'extension/background.js'],
'sidebar-css-interaction': ['browse/src/server.ts', 'browse/src/sidebar-agent.ts', 'browse/src/write-commands.ts', 'browse/src/read-commands.ts', 'browse/src/cdp-inspector.ts', 'extension/**'],
// Autoplan
'autoplan-core': ['autoplan/**', 'plan-ceo-review/**', 'plan-eng-review/**', 'plan-design-review/**'],
@@ -648,7 +643,6 @@ export const E2E_TIERS: Record<string, 'gate' | 'periodic'> = {
'ship-triage': 'gate',
'ship-plan-completion': 'gate',
'ship-plan-verification': 'gate',
'ship-idempotency': 'periodic',
// Retro — gate for cheap branch detection, periodic for full Opus retro
'retro': 'periodic',
@@ -702,10 +696,6 @@ export const E2E_TIERS: Record<string, 'gate' | 'periodic'> = {
'benchmark-workflow': 'gate',
'setup-deploy-workflow': 'gate',
// Sidebar agent
'sidebar-navigate': 'periodic',
'sidebar-url-accuracy': 'periodic',
'sidebar-css-interaction': 'periodic',
// Autoplan — periodic (not yet implemented)
'autoplan-core': 'periodic',
@@ -776,7 +766,6 @@ export const LLM_JUDGE_TOUCHFILES: Record<string, string[]> = {
'plan-eng-review/SKILL.md sections': ['plan-eng-review/SKILL.md', 'plan-eng-review/SKILL.md.tmpl'],
// /spec authored-spec quality (paid LLM-judge — periodic-tier).
'spec authored quality': ['spec/SKILL.md', 'spec/SKILL.md.tmpl', 'test/fixtures/spec/**'],
'plan-design-review/SKILL.md passes': ['plan-design-review/SKILL.md', 'plan-design-review/SKILL.md.tmpl'],
// Design skills