diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dec15117..8770a92ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [1.91.166.0] - 2026-10-20 + +**Two load-sensitive free tests from the flaky ledger now measure what they test.** Daily flaky-fix pass, 2026-10-20, free and load-sensitive group. + +### Fixed +- **`test/setup-ps1.test.ts` PowerShell 5.1 cases (windows-setup, 2026-10-17 and 2026-10-20).** The workflow runs the file with plain `bun test`, so each case has Bun's 5 s default. The first `powershell.exe` launch on a runner pays a cold start that later launches do not. Over 94 windows-setup jobs, the first legacy launch (the space-in-TMPDIR case) took p50 1.46 s, p95 3.42 s and max 5.04 s, while the second launch (the empty-argument case) had p95 1.41 s. Both reds were that first launch killed at 5 s with exit null. A `beforeAll` now launches the legacy interpreter once on the stub checkout, with a 60 s hook budget matching the spawns' own bound. No per-test timeout changed. On Linux, a pwsh wrapper that adds 6 s to the first launch reproduces the CI symptom on main and passes with the warm-up. One that adds 6 s to every launch still fails three cases (negative control). +- **`browse/test/xvfb.test.ts` spawn → cleanup round trip (Ubicloud full run, 2026-10-18).** It picked a display from `:99-:110` and then spawned on it, inside the default range that headed daemons in parallel shards allocate from. Six default-range allocators reproduced "X display :N was reserved by another X server during startup" in 9 of 20 and 5 of 20 runs. The case now uses `:25000-:25100`, a range no other allocator uses, like the file's other private-range cases. It now fails instead of silently returning when no display is free. 30 of 30 runs pass under the same load. + ## [1.91.165.0] - 2026-10-20 **The Version Gate accepts an unstamped READY head under merge trains.** Under the train policy a lane's head keeps VERSION, package.json and the agents digest at main's version and writes its CHANGELOG entry under `[Unreleased]`. The gate still demanded a bump, so every unstamped PR showed "VERSION not bumped", and `gstack-ship-queue ready` refused it with `QUEUE_NOT_READY` (#3320, #3321). That blocked every train. Plan GSTA-49, S1 for the queue. diff --git a/VERSION b/VERSION index 1fcb45616..4bf604b4d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.165.0 +1.91.166.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 6c984b2b3..70bf2dc63 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.165.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.166.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/browse/test/xvfb.test.ts b/browse/test/xvfb.test.ts index ff2164eda..d6c508541 100644 --- a/browse/test/xvfb.test.ts +++ b/browse/test/xvfb.test.ts @@ -157,12 +157,11 @@ describe('pickFreeDisplay (Xvfb installed)', () => { describe('xvfb spawn → cleanup round trip (Linux + Xvfb only)', () => { test.skipIf(!HAS_XVFB)('spawn, validate ownership, cleanup', async () => { const { spawnXvfb } = await import('../src/xvfb'); - const display = pickFreeDisplay(99, 110); - if (display == null) { - // No free display in range — skip. - return; - } - const handle = await spawnXvfb(display); + // A range no other allocator in the suite uses: headed daemons in parallel + // shards take displays from the default :99-:120 between this pick and the spawn. + const display = pickFreeDisplay(25000, 25100); + expect(display).not.toBeNull(); + const handle = await spawnXvfb(display!); try { expect(handle.pid).toBeGreaterThan(0); expect(handle.display).toBe(`:${display}`); @@ -173,7 +172,7 @@ describe('xvfb spawn → cleanup round trip (Linux + Xvfb only)', () => { const lock = fs.readFileSync(lockPath, 'utf8'); cleanupXvfb({ ...handle, startTime: 'stale-start-time' }); expect(isOurXvfb(handle.pid, handle.startTime)).toBe(true); - await expect(spawnXvfb(display)).rejects.toThrow('already reserved'); + await expect(spawnXvfb(display!)).rejects.toThrow('already reserved'); expect(fs.readFileSync(lockPath, 'utf8')).toBe(lock); expect(isOurXvfb(handle.pid, handle.startTime)).toBe(true); } finally { diff --git a/package.json b/package.json index 923c34ba4..55ddf7b14 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.165", + "version": "1.91.166", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/setup-ps1.test.ts b/test/setup-ps1.test.ts index 690dfeed6..ca6292209 100644 --- a/test/setup-ps1.test.ts +++ b/test/setup-ps1.test.ts @@ -8,7 +8,7 @@ * (#3130: the 5.1 legacy mode stripped the double quotes inside the bash -c * script, and bash failed with "unexpected EOF"). */ -import { describe, test, expect, afterEach } from 'bun:test'; +import { describe, test, expect, afterEach, beforeAll } from 'bun:test'; import * as fs from 'fs'; import * as os from 'os'; import * as path from 'path'; @@ -65,6 +65,13 @@ function runPs1(dir: string, args: string[], env: Record { + // The first Windows PowerShell 5.1 launch on a runner pays a cold start (up to + // 5 s on windows-latest) that later launches do not; pay it here, outside the + // per-test timeout of the legacy cases below. + beforeAll(() => { + if ((PWSH || IS_WIN) && BASH) runPs1Legacy(stubCheckout(), ['--host', 'codex']); + }, 60_000); + test('passes arguments NUL-separated through a private file to a constant bash script', () => { expect(SOURCE).toContain(`& $bash -c 'set -f; IFS=; mapfile -d '''' -t argv < $1; rm -f -- $1; exec ./setup \${argv[@]}' setup $argFile`); const script = SOURCE.match(/& \$bash -c '((?:[^']|'')*)' setup \$argFile/)![1]!;