v1.87.5.0 perf: remove idle waits from tests and CI planning (#2897)

* v1.87.5.0 perf: remove idle waits from tests and CI planning

* fix: settle split PTY redraws before routing input

* docs: record final burst-safe test benchmarks

* fix: keep cold-setup snapshot metadata dependency-free

* fix: avoid early-reader pipe races in artifact URL parsing

* fix: preserve safety matches for multiline command payloads

* fix: recognize concurrent CSO publication removal

* test: preload the UI design-review target before invocation

* docs: record validation blocker fixes

* fix: bind plan observer rejection to the invoked command

* fix: count only native design decisions in the UI gate

* docs: clarify UI-positive eval evidence requirements

* test: recognize native UI decisions without weakening finding counts

* test: decouple native UI evidence from question punctuation

* test: recognize concrete native UI decisions independently of prose format

* fix: retain failed eval logs under the hidden CI cache

* test: await telemetry completion instead of racing disk writes
This commit is contained in:
Garry Tan
2026-09-21 12:27:25 -04:00
committed by GitHub
parent a6b3a57512
commit 35dd014c58
42 changed files with 1583 additions and 284 deletions
+30
View File
@@ -0,0 +1,30 @@
export interface SnapshotOptions {
interactive?: boolean;
compact?: boolean;
depth?: number;
selector?: string;
diff?: boolean;
annotate?: boolean;
outputPath?: string;
cursorInteractive?: boolean;
heatmap?: string;
}
export const SNAPSHOT_FLAGS: Array<{
short: string;
long: string;
description: string;
takesValue?: boolean;
valueHint?: string;
optionKey: keyof SnapshotOptions;
}> = [
{ short: '-i', long: '--interactive', description: 'Interactive elements only (buttons, links, inputs) with @e refs. Also auto-enables cursor-interactive scan (-C) to capture dropdowns and popovers.', optionKey: 'interactive' },
{ short: '-c', long: '--compact', description: 'Compact (no empty structural nodes)', optionKey: 'compact' },
{ short: '-d', long: '--depth', description: 'Limit tree depth (0 = root only, default: unlimited)', takesValue: true, valueHint: '<N>', optionKey: 'depth' },
{ short: '-s', long: '--selector', description: 'Scope to CSS selector', takesValue: true, valueHint: '<sel>', optionKey: 'selector' },
{ short: '-D', long: '--diff', description: 'Unified diff against previous snapshot (first call stores baseline)', optionKey: 'diff' },
{ short: '-a', long: '--annotate', description: 'Annotated screenshot with red overlay boxes and ref labels', optionKey: 'annotate' },
{ short: '-o', long: '--output', description: 'Output path for annotated screenshot (default: <temp>/browse-annotated.png)', takesValue: true, valueHint: '<path>', optionKey: 'outputPath' },
{ short: '-C', long: '--cursor-interactive', description: 'Cursor-interactive elements (@c refs — divs with pointer, onclick). Auto-enabled when -i is used.', optionKey: 'cursorInteractive' },
{ short: '-H', long: '--heatmap', description: 'Color-coded overlay screenshot from JSON map: \'{"@e1":"green","@e3":"red"}\'. Valid colors: green, yellow, red, blue, orange, gray.', takesValue: true, valueHint: '<json>', optionKey: 'heatmap' },
];
+3 -38
View File
@@ -24,6 +24,9 @@ import { TEMP_DIR, isPathWithin } from './platform';
import { escapeEnvelopeSentinels } from './content-security';
import { stripLoneSurrogates } from './sanitize';
import { guardScreenshotPath } from './screenshot-size-guard';
import { SNAPSHOT_FLAGS, type SnapshotOptions } from './snapshot-flags';
export { SNAPSHOT_FLAGS } from './snapshot-flags';
// Roles considered "interactive" for the -i flag
const INTERACTIVE_ROLES = new Set([
@@ -33,44 +36,6 @@ const INTERACTIVE_ROLES = new Set([
'treeitem',
]);
interface SnapshotOptions {
interactive?: boolean; // -i: only interactive elements
compact?: boolean; // -c: remove empty structural elements
depth?: number; // -d N: limit tree depth
selector?: string; // -s SEL: scope to CSS selector
diff?: boolean; // -D / --diff: diff against last snapshot
annotate?: boolean; // -a / --annotate: annotated screenshot
outputPath?: string; // -o / --output: path for annotated screenshot
cursorInteractive?: boolean; // -C / --cursor-interactive: scan cursor:pointer etc.
heatmap?: string; // -H / --heatmap: JSON color map for ref overlays
}
/**
* Snapshot flag metadata — single source of truth for CLI parsing and doc generation.
*
* Imported by:
* - gen-skill-docs.ts (generates {{SNAPSHOT_FLAGS}} tables)
* - skill-parser.ts (validates flags in SKILL.md examples)
*/
export const SNAPSHOT_FLAGS: Array<{
short: string;
long: string;
description: string;
takesValue?: boolean;
valueHint?: string;
optionKey: keyof SnapshotOptions;
}> = [
{ short: '-i', long: '--interactive', description: 'Interactive elements only (buttons, links, inputs) with @e refs. Also auto-enables cursor-interactive scan (-C) to capture dropdowns and popovers.', optionKey: 'interactive' },
{ short: '-c', long: '--compact', description: 'Compact (no empty structural nodes)', optionKey: 'compact' },
{ short: '-d', long: '--depth', description: 'Limit tree depth (0 = root only, default: unlimited)', takesValue: true, valueHint: '<N>', optionKey: 'depth' },
{ short: '-s', long: '--selector', description: 'Scope to CSS selector', takesValue: true, valueHint: '<sel>', optionKey: 'selector' },
{ short: '-D', long: '--diff', description: 'Unified diff against previous snapshot (first call stores baseline)', optionKey: 'diff' },
{ short: '-a', long: '--annotate', description: 'Annotated screenshot with red overlay boxes and ref labels', optionKey: 'annotate' },
{ short: '-o', long: '--output', description: 'Output path for annotated screenshot (default: <temp>/browse-annotated.png)', takesValue: true, valueHint: '<path>', optionKey: 'outputPath' },
{ short: '-C', long: '--cursor-interactive', description: 'Cursor-interactive elements (@c refs — divs with pointer, onclick). Auto-enabled when -i is used.', optionKey: 'cursorInteractive' },
{ short: '-H', long: '--heatmap', description: 'Color-coded overlay screenshot from JSON map: \'{"@e1":"green","@e3":"red"}\'. Valid colors: green, yellow, red, blue, orange, gray.', takesValue: true, valueHint: '<json>', optionKey: 'heatmap' },
];
interface ParsedNode {
indent: number;
role: string;
+3 -3
View File
@@ -97,10 +97,10 @@ export interface TelemetryEvent {
}
/** Fire-and-forget log. Never throws. */
export function logTelemetry(payload: TelemetryEvent): void {
if (isTelemetryDisabled()) return;
export function logTelemetry(payload: TelemetryEvent): Promise<void> {
if (isTelemetryDisabled()) return Promise.resolve();
const enriched = { ...payload, ts: new Date().toISOString() };
ensureDir()
return ensureDir()
.then(() => fs.appendFile(telemetryFile(), JSON.stringify(enriched) + '\n', 'utf8'))
.catch(() => {
// Telemetry must never crash the caller. If the disk is full or perms
+9 -6
View File
@@ -114,10 +114,11 @@ describe('bun-polyfill', () => {
const p = Bun.spawn(['this-binary-does-not-exist-zzz-' + Date.now()], {
stdio: ['ignore', 'pipe', 'pipe']
});
let deadline;
const code = await Promise.race([
p.exited,
new Promise((_, r) => setTimeout(() => r(new Error('timeout')), 3000))
]).catch(() => 'TIMEOUT');
new Promise((_, r) => { deadline = setTimeout(() => r(new Error('timeout')), 3000); })
]).catch(() => 'TIMEOUT').finally(() => clearTimeout(deadline));
console.log('exit:' + code);
})();
`], { stdout: 'pipe', stderr: 'pipe', timeout: 30_000 });
@@ -159,10 +160,11 @@ describe('bun-polyfill', () => {
['node', '-e', 'process.stdout.write("y".repeat(10 * 1024)); process.exit(0)'],
{ stdio: ['ignore', 'pipe', 'ignore'] }
);
let deadline;
const code = await Promise.race([
p.exited,
new Promise((_, r) => setTimeout(() => r(new Error('timeout')), 3000))
]).catch(() => 'TIMEOUT');
new Promise((_, r) => { deadline = setTimeout(() => r(new Error('timeout')), 3000); })
]).catch(() => 'TIMEOUT').finally(() => clearTimeout(deadline));
const out = await new Response(p.stdout).text();
console.log(out.length + ':' + code);
})();
@@ -190,10 +192,11 @@ describe('bun-polyfill', () => {
['node', '-e', 'process.stdout.write("x".repeat(' + ONE_MB + '), () => process.exit(0))'],
{ stdio: ['ignore', 'pipe', 'ignore'] }
);
let deadline;
const code = await Promise.race([
p.exited,
new Promise((_, r) => setTimeout(() => r(new Error('timeout')), 10000))
]).catch(e => 'TIMEOUT');
new Promise((_, r) => { deadline = setTimeout(() => r(new Error('timeout')), 10000); })
]).catch(e => 'TIMEOUT').finally(() => clearTimeout(deadline));
const out = await new Response(p.stdout).text();
console.log(out.length + ':' + code);
})().catch((e) => { console.log('THREW:' + e.message); });
+11 -1
View File
@@ -6,9 +6,19 @@
* CORS headers, and JSON response formats.
*/
import { describe, test, expect } from 'bun:test';
import { afterAll, describe, test, expect } from 'bun:test';
import { handleCookiePickerRoute, generatePickerCode, hasActivePicker } from '../src/cookie-picker-routes';
afterAll(() => {
const realNow = Date.now;
Date.now = () => realNow() + 3_700_000;
try {
expect(hasActivePicker()).toBe(false);
} finally {
Date.now = realNow;
}
});
// ─── Mock BrowserManager ──────────────────────────────────────
function mockBrowserManager() {
+3 -7
View File
@@ -151,23 +151,19 @@ describe('telemetry env tier + cache semantics', () => {
describe('enforcement: logTelemetry writes only with granted consent', () => {
test('config-tier opt-out suppresses the JSONL append', async () => {
const dir = tmpHomeWith('telemetry: off\n');
logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
// Fire-and-forget path: give any (incorrect) async append time to land.
await new Promise((r) => setTimeout(r, 30));
await logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
expect(fs.existsSync(path.join(dir, 'analytics', 'browse-telemetry.jsonl'))).toBe(false);
});
test('no consent ever recorded (absent key) suppresses the JSONL append', async () => {
const dir = tmpHomeWith('pair_agent: on\n');
logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
await new Promise((r) => setTimeout(r, 30));
await logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
expect(fs.existsSync(path.join(dir, 'analytics', 'browse-telemetry.jsonl'))).toBe(false);
});
test('granted `community` tier appends the event', async () => {
const dir = tmpHomeWith('telemetry: community\n');
logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
await new Promise((r) => setTimeout(r, 30));
await logTelemetry({ event: 'domain_skill_fired', host: 'example.com' });
const file = path.join(dir, 'analytics', 'browse-telemetry.jsonl');
expect(fs.existsSync(file)).toBe(true);
expect(fs.readFileSync(file, 'utf-8')).toContain('domain_skill_fired');
+5 -5
View File
@@ -33,8 +33,6 @@ afterAll(async () => {
});
async function readEvents(): Promise<any[]> {
// Wait briefly for fire-and-forget appends to flush.
await new Promise((r) => setTimeout(r, 30));
try {
const raw = await fs.readFile(TELEMETRY_FILE, 'utf8');
return raw.trim().split('\n').filter(Boolean).map((l) => JSON.parse(l));
@@ -47,7 +45,7 @@ describe('telemetry: signals fire to ~/.gstack/analytics/browse-telemetry.jsonl'
it('logTelemetry writes a JSONL line with ts injected', async () => {
const { logTelemetry, _resetTelemetryCache } = await import('../src/telemetry');
_resetTelemetryCache();
logTelemetry({ event: 'domain_skill_saved', host: 'test.com', scope: 'project', state: 'quarantined', bytes: 42 });
await logTelemetry({ event: 'domain_skill_saved', host: 'test.com', scope: 'project', state: 'quarantined', bytes: 42 });
const events = await readEvents();
expect(events).toHaveLength(1);
expect(events[0].event).toBe('domain_skill_saved');
@@ -60,7 +58,7 @@ describe('telemetry: signals fire to ~/.gstack/analytics/browse-telemetry.jsonl'
process.env.GSTACK_TELEMETRY_OFF = '1';
const { logTelemetry, _resetTelemetryCache } = await import('../src/telemetry');
_resetTelemetryCache();
logTelemetry({ event: 'cdp_method_called', domain: 'X', method: 'y' });
await logTelemetry({ event: 'cdp_method_called', domain: 'X', method: 'y' });
const events = await readEvents();
expect(events).toHaveLength(0);
process.env.GSTACK_TELEMETRY_OFF = '0';
@@ -72,6 +70,8 @@ describe('telemetry: signals fire to ~/.gstack/analytics/browse-telemetry.jsonl'
// logTelemetry on a missing directory doesn't throw.
const { logTelemetry, _resetTelemetryCache } = await import('../src/telemetry');
_resetTelemetryCache();
expect(() => logTelemetry({ event: 'noop_test' })).not.toThrow();
let completed: Promise<void> | undefined;
expect(() => { completed = logTelemetry({ event: 'noop_test' }); }).not.toThrow();
await completed;
});
});
+10 -4
View File
@@ -43,8 +43,7 @@ afterEach(async () => {
// Kill any survivors so subsequent tests get a clean slate.
try { parentProc?.kill('SIGKILL'); } catch {}
try { serverProc?.kill('SIGKILL'); } catch {}
// Give processes a moment to exit before tmpDir cleanup.
await Bun.sleep(100);
await Promise.all([parentProc?.exited, serverProc?.exited]);
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
parentProc = null;
serverProc = null;
@@ -316,7 +315,13 @@ describe('suppressed watchdog still reaps tunnel orphans (behavioral)', () => {
});
test('CRITICAL: suppression active + tunnel live — parent death still shuts down', async () => {
const exitMock = mock((_code?: number) => {});
let resolveExit!: () => void;
let exitDeadline!: ReturnType<typeof setTimeout>;
const exited = new Promise<void>((resolve, reject) => {
resolveExit = resolve;
exitDeadline = setTimeout(() => reject(new Error('Watchdog shutdown did not exit within 3s')), 3_000);
});
const exitMock = mock((_code?: number) => { resolveExit(); });
const originalExit = process.exit;
(process as any).exit = exitMock;
try {
@@ -324,12 +329,13 @@ describe('suppressed watchdog still reaps tunnel orphans (behavioral)', () => {
__testInternals__.suppressHeadedParentShutdown();
__testInternals__.setTunnelActive(true); // handoff → resume → /pair-agent tunnel
__testInternals__.parentWatchdogTick(DEAD_PID);
await drainShutdown();
await exited;
// The tick is the ONLY reaper for tunnel orphans (idle timeout is
// disabled in tunnel mode). If this fails, an internet-exposed daemon
// outlives its parent forever.
expect(exitMock).toHaveBeenCalled();
} finally {
clearTimeout(exitDeadline);
(process as any).exit = originalExit;
}
});