[eric] ci: the Windows leg's three failures were the harness, not the code: --import needs a file URL, autocrlf broke every source-pin test (LF pinned), the suite runs under the product's PYTHONUTF8; a poll test waits on state, not a clock (ENG-486)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ciregenz
2026-09-06 18:17:28 -07:00
co-authored by Claude Fable 5.1
parent 9d68ac6d5d
commit 28684b7a81
5 changed files with 30 additions and 5 deletions
+3
View File
@@ -4,3 +4,6 @@
# anything nested. Together they exclude all 3 bundles from language stats.
backend/mcp-bundles/* linguist-vendored
backend/mcp-bundles/**/* linguist-vendored
# Source-pin tests read files and match on \n; a Windows checkout with autocrlf turned every one red. LF everywhere, on every OS.
* text=auto eol=lf
+4 -1
View File
@@ -11,7 +11,8 @@ on:
concurrency:
group: suites-matrix-${{ github.ref }}
cancel-in-progress: true
# A run in flight keeps its verdicts; a push mid-run queues behind it instead of cancelling the Mac legs.
cancel-in-progress: false
permissions:
contents: read
@@ -27,6 +28,8 @@ jobs:
env:
OSW_NEVER_KILL_ROUTER: '1'
OSW_DISABLE_AUTO_RESUME: '1'
# The packaged app spawns its backend with PYTHONUTF8=1 (electron/main.js); the suite runs the way the product runs, or Windows' cp1252 default fails collection on the first source read.
PYTHONUTF8: '1'
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
steps:
- uses: actions/checkout@v4
+7 -3
View File
@@ -630,9 +630,13 @@ test("poll loop respects max attempts and gives up", async () => {
isPackaged: true,
});
// Wait long enough for all attempts to fail. 20ms × 30 = 600ms.
await delay(900);
const state = readJson(path.join(userDataDir, "install.json"));
// Wait for the loop to record its last attempt, not for a clock: a fixed 900ms saw 29 of 30 on a loaded Mac.
let state = {};
for (let i = 0; i < 200; i++) {
state = readJson(path.join(userDataDir, "install.json"));
if (state.attempts === 30) break;
await delay(50);
}
assert.equal(state.ref, null, "no ref after exhausted polls");
assert.equal(state.attempts, 30, "all attempts recorded");
});
+13
View File
@@ -0,0 +1,13 @@
const { test } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('fs');
const path = require('path');
// 46 reads in backend/apps open text files without naming an encoding; on Windows the default is
// cp1252 and the first non-Latin byte raises. The packaged spawn declares UTF-8, and the CI suites
// run under the same declaration (suites-matrix.yml), so the two must not drift apart.
test('every backend spawn in main.js declares PYTHONUTF8=1', () => {
const main = fs.readFileSync(path.join(__dirname, 'main.js'), 'utf8');
const spawns = main.match(/PYTHONUTF8: '1'/g) || [];
assert.ok(spawns.length >= 2, `expected the dev and packaged spawn envs to carry PYTHONUTF8, found ${spawns.length}`);
});
+3 -1
View File
@@ -10,6 +10,7 @@ import { globSync } from 'node:fs';
import { mkdirSync, rmSync } from 'node:fs';
import path from 'node:path';
import { spawnSync } from 'node:child_process';
import { pathToFileURL } from 'node:url';
import { fileURLToPath } from 'node:url';
const root = path.dirname(fileURLToPath(import.meta.url)) + '/..';
@@ -47,7 +48,8 @@ try {
});
const built = globSync('**/*.mjs', { cwd: outDir }).concat(globSync('**/*.js', { cwd: outDir }));
const setup = path.join(root, 'scripts/test-globals.mjs');
const res = spawnSync(process.execPath, ['--import', setup, '--test', ...built.map((f) => path.join(outDir, f))],
// --import takes a URL: a bare Windows path (D:\...) is read as protocol 'd:' and every test file fails before it starts.
const res = spawnSync(process.execPath, ['--import', pathToFileURL(setup).href, '--test', ...built.map((f) => path.join(outDir, f))],
{ stdio: 'inherit', cwd: root });
status = res.status ?? 1;
} finally {