igneum/tools/ci/second-engine-check.sh
igneum-labs 3d505766d2 C35 named: PC 1's 22:31 UTC quit was the per-user installer launched by the second engine's own updater (0.3.9 under min_supported_version = urgent, beating auto_update = false); a second engine never runs the updater (IGNEUM_APP_NO_OTA=1, implied by --sweep; the playbooks set it; the CI check demands it); bench log and plan carry the named source
Source: the scratch engine's own log in collect ember-c35-collect-1 (06:59Z): 22:31:02Z '0.3.10 is available: downloading',
22:31:05Z 'update: starting the installer first ... ota-apply.ps1', and the installed app's 'quit:' at 22:31:06Z.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-06 07:01:57 +00:00

28 lines
2.3 KiB
Bash
Executable file

#!/usr/bin/env bash
# The second-engine class (C35, 5 October 2026, PC 1 22:31 UTC): a playbook started a second Igneum engine beside the
# installed app through a redirected PIPE (PowerShell's Process.Start with RedirectStandardOutput). A pipe's write end is
# inherited by every process the engine starts (its miners and workers); when the job was aborted, the installed app's
# jobs runner waited for an EOF the orphaned grandchildren never sent and its quit hung for 24 minutes, and the second
# engine's miners mined on against the relaunched app. Rule for every playbook that starts an engine: (1) the engine's
# output goes to a FILE (Start-Process -RedirectStandardOutput <file>), never a pipe into the script; (2) the engine's
# whole process tree is ended at the end and on the budget (taskkill /T /F), so nothing is orphaned; the installed
# app's miners come back only after that (the job runner restarts them when the script ends). This check fails CI when
# a playbook starts an engine without both, or without IGNEUM_APP_NO_OTA = '1' (the third line, same night: the second
# engine's updater found itself under min_supported_version and ran the installer, which quit the installed app).
set -euo pipefail
cd "$(dirname "$0")/../.."
fail=0
while IFS= read -r f; do
grep -qE "igneum-app(\.exe)?['\"]? *(--sweep|-ArgumentList '--sweep'|--no-open)|ArgumentList '--sweep'|\.Arguments = '--sweep'" "$f" || continue
if grep -qE 'RedirectStandardOutput *= *\$true|UseShellExecute *= *\$false|Register-ObjectEvent|BeginOutputReadLine' "$f"; then
echo "second-engine: $f starts an engine through a pipe (RedirectStandardOutput/BeginOutputReadLine); use Start-Process -RedirectStandardOutput <file>"; fail=1
fi
if ! grep -qE 'taskkill /T /F' "$f"; then
echo "second-engine: $f starts an engine without ending its process tree (taskkill /T /F) at the end"; fail=1
fi
if ! grep -qE "IGNEUM_APP_NO_OTA *= *'1'" "$f"; then
echo "second-engine: $f starts an engine without IGNEUM_APP_NO_OTA = '1' (its updater would run the installer, which quits the installed app: PC 1, 5 October 2026, 22:31 UTC)"; fail=1
fi
done < <(git ls-files 'relay/playbooks/**' 'tools/windows/**' 'packaging/**' | grep -E '\.ps1$')
[ "$fail" = 0 ] && echo "second-engine: every playbook that starts an engine logs to a file and ends its tree"
exit $fail