From ec5508e978249d4d6180b029ec5d16e610ff28fb Mon Sep 17 00:00:00 2001 From: dh Date: Mon, 5 Oct 2026 13:09:47 +0200 Subject: [PATCH] Admit the existing runner with an explicit guest and QEMU memory budget --- docs/macos-native-diagnostic.md | 2 ++ tools/ci/MacOsNativeDiagnostic.cs | 27 ++++++++++++++++++++++++--- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/macos-native-diagnostic.md b/docs/macos-native-diagnostic.md index 4e0ace4..0b3fe37 100644 --- a/docs/macos-native-diagnostic.md +++ b/docs/macos-native-diagnostic.md @@ -4,6 +4,8 @@ The isolated RAW Recovery comparison starts from Full candidate `2e2d702e294c39f The existing pinned container's `qemu-img` converts the already-patched DMG, requires sector equality with `qemu-img compare`, and checks that conversion preserved the DMG's SHA256. Both images stay in this run's owned storage. A retained JSON receipt binds both hashes and the successful comparison. The original readonly virtio attachment and I/O thread are preserved; cleanup removes both images with that owned volume. Local `--validate --full --recovery-format raw --source --output ` exercises conversion failures, source mutation and strict backend selection with a mocked QEMU boundary. The generated `raw-recovery-real-qemu-fixture.sh` accepts an already-patched **disposable writable DMG copy** plus destination for an actual container QEMU comparison; it does not patch, mount or boot a guest. This comparison does not yet prove faster guest operation or native application tests. +Run 4204 stopped before creating a VM because the shared host exposed 5,138,696 KiB available memory, just below the previous arbitrary 5-GiB admission threshold. Admission now budgets the unchanged 4-GiB guest plus 512 MiB for QEMU (4.5 GiB); previous guest recordings peaked below 3 GiB. The 6-GiB container cap and all guest parameters remain unchanged. Offline validation replays that captured host value and still rejects a host with only 4 GiB available. This is an admission budget, not a reservation against other host workloads; actual performance and memory remain subject to the remote result. + This manual candidate uses the existing Ubuntu/x64 Docker runner. Before downloading Apple Recovery it tests actual AVX/AVX2 instruction execution in the pinned QEMU binary, then probes a fresh macOS 14+ Recovery guest. It does not install macOS, erase a disk, provision .NET/CLT or run Meeting Assistant tests. Readiness is only a prerequisite for full native CI. ## Profile and evidence diff --git a/tools/ci/MacOsNativeDiagnostic.cs b/tools/ci/MacOsNativeDiagnostic.cs index 1bdb8e6..459fb12 100644 --- a/tools/ci/MacOsNativeDiagnostic.cs +++ b/tools/ci/MacOsNativeDiagnostic.cs @@ -78,6 +78,7 @@ static class NativeDiagnostic if (recoveryFormat is not ("dmg" or "raw")) throw new ArgumentException("Recovery format must be dmg or raw."); if (args.Contains("--validate")) { + ValidateRunnerMemoryGate(); ValidateContracts(); ValidateBootProgress(); ValidateDiskStackCapture(output); @@ -168,9 +169,8 @@ static class NativeDiagnostic throw new InvalidOperationException("Existing Docker resources cannot fit this bounded 2-CPU/6-GiB diagnostic; no infrastructure change was requested."); } await Command("sh", ["-c", "cat /proc/meminfo; printf '\n[cgroup]\n'; cat /sys/fs/cgroup/memory.max /sys/fs/cgroup/cpu.max 2>/dev/null || true; printf '\n[workspace disk]\n'; df -Pk ."], output, "runner-resources", deadline.Token); - var available = System.Text.RegularExpressions.Regex.Match(File.ReadAllText("/proc/meminfo"), @"(?m)^MemAvailable:\s+(\d+) kB$"); - if (!available.Success || long.Parse(available.Groups[1].Value) < 5L * 1024 * 1024) - throw new InvalidOperationException("Existing runner memory has less than the 5-GiB available diagnostic budget; no infrastructure change was requested."); + if (!HasAvailableGuestMemory(File.ReadAllText("/proc/meminfo"))) + throw new InvalidOperationException("Existing runner memory cannot fit the 4-GiB guest plus its 512-MiB QEMU overhead budget; no infrastructure change was requested."); var source = Path.Combine(work, "dockur"); await Command("git", ["clone", "--no-checkout", "https://github.com/dockur/macos.git", source], output, "dockur-clone", deadline.Token); await Command("git", ["-C", source, "checkout", "--detach", DockurCommit], output, "dockur-checkout", deadline.Token); @@ -481,6 +481,27 @@ static class NativeDiagnostic File.WriteAllBytes(Path.Combine(probeAssets, "build-manifest.json"), probe.Manifest); } + static bool HasAvailableGuestMemory(string meminfo) + { + var available = System.Text.RegularExpressions.Regex.Match(meminfo, @"(?m)^MemAvailable:\s+(\d+) kB$"); + return available.Success && long.TryParse(available.Groups[1].Value, out var kib) && kib >= 4L * 1024 * 1024 + 512L * 1024; + } + + static void ValidateRunnerMemoryGate() + { + // Run 4204: 4-GiB guest plus 512-MiB QEMU overhead fits its captured available memory. + var cases = new[] + { + ("captured-run4204", "MemTotal: 16281732 kB\nMemAvailable: 5138696 kB\n", true), + ("below-guest-plus-overhead", "MemAvailable: 4194304 kB\n", false), + ("missing", "MemTotal: 16281732 kB\n", false), + ("invalid", "MemAvailable: unavailable kB\n", false) + }; + foreach (var (name, meminfo, expected) in cases) + if (HasAvailableGuestMemory(meminfo) != expected) + throw new InvalidOperationException("Existing runner memory admission failed: " + name); + } + static readonly string RawRecoveryPreparation = """ local raw="$dest.raw" pending="$dest.raw.tmp" source_hash after_hash raw_hash [ ! -e "$raw" ] && [ ! -e "$pending" ] && [ ! -e "$raw.json" ] || {