From 59adbb0d1a1eedff70172421290dfc08fd4b698f Mon Sep 17 00:00:00 2001 From: SUaDtL Date: Sun, 26 Jul 2026 10:11:25 -0400 Subject: [PATCH] fix(pi): a 5s test deadline cannot cover a cold Python launch on Windows The pi security-evidence test fails on windows-latest with "Test timed out in 5000ms" - a harness timeout, not an assertion. Seen three times on 2026-07-26 across two branches and both pinned Pi runtimes, while ubuntu-latest and macos-latest passed every one of those runs. It fails on main too (run 30203161506), so it is not branch-specific. The script is not the slow part: `test_pi_security.py --contract-only` runs in about 70ms, and it imports nothing this repository changed recently. What does not fit in 5s is a cold CPython process launch on a loaded Windows runner, and the whole cost lands inside the test's budget because the spawn is synchronous. The deadline was provisioned for the script's runtime when what it has to cover is a process creation. So the timeout is what is wrong, not the code under test, and it is now platform-aware rather than uniformly larger - a genuine hang on the fast platforms still surfaces as a hang. Both tests in the file that spawn Python synchronously get it, so the second does not resurface separately (AC-4). No assertion is touched: the secret-bearing ambient-value checks are unchanged. This is not cosmetic. `[GATE ] | [REPO] | Merge readiness` aggregates this suite, and the release preflight requires that gate green for the EXACT commit being tagged (#385), so a flake here blocks the release lane for that SHA and trains readers to re-run a red gate without reading it. It cost two merge attempts on PR #494. No version bump: plugins/ca-pi/tools/** is outside the shipped payload (payload_scope.py), and this changes a test only. Closes #495 Claude-Session: https://claude.ai/code/session_01Y8UPz5RZwgnda3NbAVfd6L --- .codearbiter/gate-events.log | 1 + plugins/ca-pi/tools/test/security.test.ts | 20 ++++++++++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/.codearbiter/gate-events.log b/.codearbiter/gate-events.log index 8d122ef1..eb67c490 100644 --- a/.codearbiter/gate-events.log +++ b/.codearbiter/gate-events.log @@ -974,3 +974,4 @@ Claude-Session: https://claude.ai/code/session_015ZDVU1BzUqnnPVHbZ397bX') stages [2026-07-20T05:54:34Z] BLOCK [H-05] host=claude hook=pre-bash.py | The .codearbiter audit logs (overrides.log, triage.log, sprint-log.md, gate-events.log) are append-only (ORCHESTRATOR §7). Truncating, overwriting, or deleting the audit trail is prohibited; append with '>>' only. [2026-07-20T05:54:34Z] BLOCK [H-05] host=claude hook=pre-bash.py | The .codearbiter audit logs (overrides.log, triage.log, sprint-log.md, gate-events.log) are append-only (ORCHESTRATOR §7). Truncating, overwriting, or deleting the audit trail is prohibited; append with '>>' only. [2026-07-20T05:54:34Z] BLOCK [H-05] host=claude hook=pre-bash.py | The .codearbiter audit logs (overrides.log, triage.log, sprint-log.md, gate-events.log) are append-only (ORCHESTRATOR §7). Truncating, overwriting, or deleting the audit trail is prohibited; append with '>>' only. +[2026-07-26T14:10:47Z] REMIND [H-12] hook=post-write-edit.py | plugins/ca-pi/tools/test/security.test.ts is governed by ADR-0013 (Add ca-pi as a sibling governance plugin using the shared core and a thin Pi adapter). If this change contradicts it, route to /ca:reconcile or /ca:adr — do not drift silently. diff --git a/plugins/ca-pi/tools/test/security.test.ts b/plugins/ca-pi/tools/test/security.test.ts index 03c9159d..8b013cf0 100644 --- a/plugins/ca-pi/tools/test/security.test.ts +++ b/plugins/ca-pi/tools/test/security.test.ts @@ -409,6 +409,22 @@ describe("ADR-0014 adversarial promotion contract", () => { expect(workflow).toContain("test_pi_security.py --sarif"); }); + // #495: the two tests below each launch a cold CPython process SYNCHRONOUSLY, + // so the wait is billed against the test's own deadline. The script is not the + // slow part - `test_pi_security.py --contract-only` runs in about 70ms. What + // does not fit in vitest's default 5s is process creation plus interpreter + // startup on a loaded windows-latest runner, where both are an order of + // magnitude more expensive than on Linux; ubuntu and macos passed every run + // that windows failed. The deadline therefore has to cover a process LAUNCH, + // not a computation, and it is platform-aware rather than uniformly larger so + // a genuine hang on the fast platforms still surfaces as a hang. + // + // This is not cosmetic. `[GATE ] | [REPO] | Merge readiness` aggregates this + // suite, and the release preflight requires that gate green for the EXACT + // commit being tagged (#385) - so a flake here blocks the release lane for that + // SHA, and trains readers to re-run a red gate without reading it. + const PYTHON_SPAWN_TIMEOUT_MS = process.platform === "win32" ? 30_000 : 5_000; + test("security evidence output is result-code-only even with secret-bearing ambient values", () => { const python = process.platform === "win32" ? "python" : "python3"; const script = resolve(import.meta.dirname, "../../../../.github/scripts/test_pi_security.py"); @@ -429,7 +445,7 @@ describe("ADR-0014 adversarial promotion contract", () => { expect(JSON.stringify(report)).not.toContain("prompt"); expect(JSON.stringify(report)).not.toContain("provider"); expect(JSON.stringify(report)).not.toContain("stderr"); - }); + }, PYTHON_SPAWN_TIMEOUT_MS); test("SARIF high gate reports only a fixed code and count", async () => { const root = await mkdtemp(resolve(tmpdir(), "ca-pi-security-sarif-")); @@ -463,7 +479,7 @@ describe("ADR-0014 adversarial promotion contract", () => { } finally { await rm(root, { recursive: true, force: true }); } - }); + }, PYTHON_SPAWN_TIMEOUT_MS); }); // Issue #464 AC-2. `security-controls.md` states that tests use disposable Pi