From 71838a01f30ecfa5bfe8e1e736518f4965f240a5 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:43:08 +0000 Subject: [PATCH 1/4] PC 1 clocks restore: the cleared helper sequence (empty cmd.txt, task restart, heartbeat) before the rgc; the third 5090 pass hit its 45 min cap at the 300 MHz step Co-Authored-By: Claude Fable 5.1 --- tools/ca3-v4-amend/pc1-clocks-restore.ps1 | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/tools/ca3-v4-amend/pc1-clocks-restore.ps1 b/tools/ca3-v4-amend/pc1-clocks-restore.ps1 index f1b550914..01033e56e 100644 --- a/tools/ca3-v4-amend/pc1-clocks-restore.ps1 +++ b/tools/ca3-v4-amend/pc1-clocks-restore.ps1 @@ -1,4 +1,5 @@ -# PC 1: put the RTX 5090's clocks back to the driver default through the Igneum Power Helper task (7 October 2026, 20:4x UTC). +# PC 1: put the RTX 5090's clocks back to the driver default through the Igneum Power Helper task (7 October 2026, 20:4x UTC; again 8 October +# 02:4x UTC after the third pass hit its time cap at the 300 MHz step, so its finally block never ran). # The second efficiency pass (run-ca3-pc1-v4-eff-5090-floor-20261007) lost the helper at its 1,000 MHz step (no helper.log line # within 30 s for that and every later command, the `nvidia-smi -lgc 0,1000` most likely hanging inside the helper), so its # closing `rgc` never ran and the card stayed at the 1,100 MHz lock (sm 1,087 on the unlocked-end rows; the live miner at 118 @@ -20,11 +21,15 @@ if (Test-Path $helperLog) { "RESULT helper.log tail: $((Get-Content -LiteralPath $task = Get-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction SilentlyContinue if (-not $task) { 'RESULT error the Igneum Power Helper task is not registered: no reset path without a prompt (Power control off)'; exit 3 } "RESULT task state before: $($task.State)" +# the cleared sequence (update-return lane, 8 October 2026, 01:17 BST): the 0.3.20 helper skips the first N lines of cmd.txt, N = the line +# count when it started, so the task is started over an EMPTY file and its heartbeat waited for before the write +Set-Content -LiteralPath $cmdFile -Value '' -NoNewline -Encoding ascii try { Stop-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop; 'RESULT task stopped' } catch { "RESULT task stop failed: $_" } -Start-Sleep -Seconds 3 -try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop; 'RESULT task started' } catch { "RESULT task start failed: $_"; exit 3 } -Start-Sleep -Seconds 3 -"RESULT task state now: $((Get-ScheduledTask -TaskName 'Igneum Power Helper').State)" +Start-Sleep -Seconds 2 +try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop; 'RESULT task started over an empty cmd.txt' } catch { "RESULT task start failed: $_"; exit 3 } +$alive = Join-Path $helperDir 'helper.alive'; $t = 0; $fresh = $false +while ($t -lt 60 -and -not $fresh) { Start-Sleep -Seconds 1; $t++; if (Test-Path -LiteralPath $alive) { try { $v = [int64]((Get-Content -LiteralPath $alive -Raw).Trim()); if (([int64][double]::Parse((Get-Date -UFormat %s)) - $v) -le 4) { $fresh = $true } } catch { } } } +"RESULT task state now: $((Get-ScheduledTask -TaskName 'Igneum Power Helper').State); heartbeat fresh=$fresh after $t s" $seq = 0 if (Test-Path $cmdFile) { $seq = @(Get-Content -LiteralPath $cmdFile -ErrorAction SilentlyContinue | ForEach-Object { if ($_ -match '^(\d{1,6})\s') { [int]$Matches[1] } }) | Measure-Object -Maximum | Select-Object -ExpandProperty Maximum } if (-not $seq) { $seq = 0 } From 63f7ae204bebbf1d7dfb979673df1f0cf3bccf19 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:47:46 +0000 Subject: [PATCH 2/4] PC 1 helper scripts: a probe dev line answered in helper.log proves the helper up when its heartbeat file stays stale (the 02:45Z restore answered with helper.alive stale past 60 s) Co-Authored-By: Claude Fable 5.1 --- tools/ca3-v4-amend/pc1-ca4-hot-ldcs.ps1 | 11 +++++++++-- tools/ca3-v4-amend/pc1-ca4-microbench.ps1 | 11 +++++++++-- tools/ca3-v4-amend/pc1-ca4-packs.ps1 | 11 +++++++++-- tools/ca3-v4-amend/pc1-v4-efficiency.ps1 | 11 +++++++++-- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/tools/ca3-v4-amend/pc1-ca4-hot-ldcs.ps1 b/tools/ca3-v4-amend/pc1-ca4-hot-ldcs.ps1 index 0bb5fe2a4..2e0994f53 100644 --- a/tools/ca3-v4-amend/pc1-ca4-hot-ldcs.ps1 +++ b/tools/ca3-v4-amend/pc1-ca4-hot-ldcs.ps1 @@ -48,8 +48,15 @@ function HelperReset() { Start-Sleep -Seconds 2 try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop } catch { $t = "$_" -replace '\s+', ' '; "RESULT helper start refused: $t"; if ($t -match '800710E0') { 'RESULT helper STOP: the scheduler refused the elevated instance (0x800710E0); nothing escalates' }; return $false } $t = 0 - while ($t -lt 60) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } - 'RESULT helper STOP: helper.alive never freshened within 60 s of the start; nothing escalates' + while ($t -lt 20) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } + # the 0.3.20 helper's heartbeat file does not freshen on every run (the 02:45Z restore: stale past 60 s, the rgc answered at once), so a + # probe dev line answered in helper.log is the proof when the heartbeat is not + $s0 = HelperSeqBase + $mark = 0; if (Test-Path $helperLog) { $mark = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue).Count } + Set-Content -LiteralPath $cmdFile -Value "$s0 dev $idx`n" -NoNewline -Encoding ascii + $t2 = 0 + while ($t2 -lt 20) { Start-Sleep -Seconds 1; $t2++; $new = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue); if ($new.Count -gt $mark -and ($new[$mark..($new.Count - 1)] | Where-Object { $_ -match "\b$s0 dev " })) { "RESULT helper up after $($t + $t2) s (the heartbeat stale, the probe dev line $s0 answered in helper.log)"; return $true } } + 'RESULT helper STOP: no heartbeat within 20 s and no answer to a probe dev line within 20 more; nothing escalates' return $false } function HelperSeqBase() { $m = 0; foreach ($f in @($cmdFile, $helperLog)) { if (Test-Path $f) { foreach ($l in (Get-Content -LiteralPath $f -ErrorAction SilentlyContinue)) { if ($l -match '(?:^|\s)(\d{1,6}) (?:dev|pl|lgc|rgc|lmc|rmc|nvidia-smi|reregister)\b') { $v = [int]$Matches[1]; if ($v -gt $m) { $m = $v } } } } }; return $m + 100 } diff --git a/tools/ca3-v4-amend/pc1-ca4-microbench.ps1 b/tools/ca3-v4-amend/pc1-ca4-microbench.ps1 index 5282b9d02..d59d5519b 100644 --- a/tools/ca3-v4-amend/pc1-ca4-microbench.ps1 +++ b/tools/ca3-v4-amend/pc1-ca4-microbench.ps1 @@ -41,8 +41,15 @@ function HelperReset() { Start-Sleep -Seconds 2 try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop } catch { $t = "$_" -replace '\s+', ' '; "RESULT helper start refused: $t"; if ($t -match '800710E0') { 'RESULT helper STOP: the scheduler refused the elevated instance (0x800710E0); nothing escalates' }; return $false } $t = 0 - while ($t -lt 60) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } - 'RESULT helper STOP: helper.alive never freshened within 60 s of the start; nothing escalates' + while ($t -lt 20) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } + # the 0.3.20 helper's heartbeat file does not freshen on every run (the 02:45Z restore: stale past 60 s, the rgc answered at once), so a + # probe dev line answered in helper.log is the proof when the heartbeat is not + $s0 = HelperSeqBase + $mark = 0; if (Test-Path $helperLog) { $mark = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue).Count } + Set-Content -LiteralPath $cmdFile -Value "$s0 dev $idx`n" -NoNewline -Encoding ascii + $t2 = 0 + while ($t2 -lt 20) { Start-Sleep -Seconds 1; $t2++; $new = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue); if ($new.Count -gt $mark -and ($new[$mark..($new.Count - 1)] | Where-Object { $_ -match "\b$s0 dev " })) { "RESULT helper up after $($t + $t2) s (the heartbeat stale, the probe dev line $s0 answered in helper.log)"; return $true } } + 'RESULT helper STOP: no heartbeat within 20 s and no answer to a probe dev line within 20 more; nothing escalates' return $false } function HelperSeqBase() { $m = 0; foreach ($f in @($cmdFile, $helperLog)) { if (Test-Path $f) { foreach ($l in (Get-Content -LiteralPath $f -ErrorAction SilentlyContinue)) { if ($l -match '(?:^|\s)(\d{1,6}) (?:dev|pl|lgc|rgc|lmc|rmc|nvidia-smi|reregister)\b') { $v = [int]$Matches[1]; if ($v -gt $m) { $m = $v } } } } }; return $m + 100 } diff --git a/tools/ca3-v4-amend/pc1-ca4-packs.ps1 b/tools/ca3-v4-amend/pc1-ca4-packs.ps1 index f75a099a2..4f9da75bf 100644 --- a/tools/ca3-v4-amend/pc1-ca4-packs.ps1 +++ b/tools/ca3-v4-amend/pc1-ca4-packs.ps1 @@ -52,8 +52,15 @@ function HelperReset() { Start-Sleep -Seconds 2 try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop } catch { $t = "$_" -replace '\s+', ' '; "RESULT helper start refused: $t"; if ($t -match '800710E0') { 'RESULT helper STOP: the scheduler refused the elevated instance (0x800710E0); nothing escalates' }; return $false } $t = 0 - while ($t -lt 60) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } - 'RESULT helper STOP: helper.alive never freshened within 60 s of the start; nothing escalates' + while ($t -lt 20) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } + # the 0.3.20 helper's heartbeat file does not freshen on every run (the 02:45Z restore: stale past 60 s, the rgc answered at once), so a + # probe dev line answered in helper.log is the proof when the heartbeat is not + $s0 = HelperSeqBase + $mark = 0; if (Test-Path $helperLog) { $mark = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue).Count } + Set-Content -LiteralPath $cmdFile -Value "$s0 dev $idx`n" -NoNewline -Encoding ascii + $t2 = 0 + while ($t2 -lt 20) { Start-Sleep -Seconds 1; $t2++; $new = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue); if ($new.Count -gt $mark -and ($new[$mark..($new.Count - 1)] | Where-Object { $_ -match "\b$s0 dev " })) { "RESULT helper up after $($t + $t2) s (the heartbeat stale, the probe dev line $s0 answered in helper.log)"; return $true } } + 'RESULT helper STOP: no heartbeat within 20 s and no answer to a probe dev line within 20 more; nothing escalates' return $false } function HelperSeqBase() { $m = 0; foreach ($f in @($cmdFile, $helperLog)) { if (Test-Path $f) { foreach ($l in (Get-Content -LiteralPath $f -ErrorAction SilentlyContinue)) { if ($l -match '(?:^|\s)(\d{1,6}) (?:dev|pl|lgc|rgc|lmc|rmc|nvidia-smi|reregister)\b') { $v = [int]$Matches[1]; if ($v -gt $m) { $m = $v } } } } }; return $m + 100 } diff --git a/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 b/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 index fb5864a46..b9eaacd1a 100644 --- a/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 +++ b/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 @@ -141,8 +141,15 @@ function HelperReset() { Start-Sleep -Seconds 2 try { Start-ScheduledTask -TaskName 'Igneum Power Helper' -ErrorAction Stop } catch { $t = "$_" -replace '\s+', ' '; "RESULT helper start refused: $t"; if ($t -match '800710E0') { 'RESULT helper STOP: the scheduler refused the elevated instance (0x800710E0); nothing escalates' }; return $false } $t = 0 - while ($t -lt 60) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } - 'RESULT helper STOP: helper.alive never freshened within 60 s of the start; nothing escalates' + while ($t -lt 20) { Start-Sleep -Seconds 1; $t++; if ((HelperAliveAge) -le 4) { "RESULT helper fresh after $t s (helper.alive within 4 s; started over an empty cmd.txt)"; return $true } } + # the 0.3.20 helper's heartbeat file does not freshen on every run (the 02:45Z restore: stale past 60 s, the rgc answered at once), so a + # probe dev line answered in helper.log is the proof when the heartbeat is not + $s0 = HelperSeqBase + $mark = 0; if (Test-Path $helperLog) { $mark = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue).Count } + Set-Content -LiteralPath $cmdFile -Value "$s0 dev $idx`n" -NoNewline -Encoding ascii + $t2 = 0 + while ($t2 -lt 20) { Start-Sleep -Seconds 1; $t2++; $new = @(Get-Content -LiteralPath $helperLog -ErrorAction SilentlyContinue); if ($new.Count -gt $mark -and ($new[$mark..($new.Count - 1)] | Where-Object { $_ -match "\b$s0 dev " })) { "RESULT helper up after $($t + $t2) s (the heartbeat stale, the probe dev line $s0 answered in helper.log)"; return $true } } + 'RESULT helper STOP: no heartbeat within 20 s and no answer to a probe dev line within 20 more; nothing escalates' return $false } function HelperSeqBase() { From 7ee6ac285505b7e9d84c53e4ed1a15ba75779f4e Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:54:13 +0000 Subject: [PATCH 3/4] PC 1 efficiency pass: the batch count follows the last rate read, and a step that would end within four minutes of the cap is not started (the third 5090 pass's cap killed the script before its restore) Co-Authored-By: Claude Fable 5.1 --- tools/ca3-v4-amend/pc1-v4-efficiency.ps1 | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 b/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 index b9eaacd1a..40ef57e99 100644 --- a/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 +++ b/tools/ca3-v4-amend/pc1-v4-efficiency.ps1 @@ -245,10 +245,15 @@ function Bench([string] $pk, [int] $n, [string] $variant = 'base') { if (-not $res -or $rc -ne 0) { $e = ($lines | Where-Object { $_ -match 'FAIL|error|MISMATCH' } | Select-Object -First 1); $err = if ($e) { ($e -replace '\s+', ' ') } else { "exit $rc, no RESULT line" } } return [pscustomobject]@{ pack = $pk; t0 = $t0; t1 = $t1; rc = $rc; fp = $fp; mhs = $mhs; check = $check; err = $err; res = $res; batches = $n; dev = $dev; variant = $variant; race = $race; served = $served; sparse = $sparse } } +# the step budget (8 October 2026: the third 5090 pass sized every step's batch count from the unlocked rate, so the 500 MHz step ran +# 155 s instead of 60 and the 45 min cap killed the script before its restore): the batch count follows the last rate read for the pack, +# and a step that would end within four minutes of the cap is not started, so the reset and the drift check run inside it +$lastMhs = @{} function Step([string] $label, [string] $lockNote) { foreach ($pk in $packOrder) { foreach ($variant in $variants) { - if ((Get-Date) -gt $deadline) { "RESULT STEP card=$cardName pack=$pk lock=$label variant=$variant error=budget spent"; continue } + if ((Get-Date) -gt $deadline.AddMinutes(-4)) { "RESULT STEP card=$cardName pack=$pk lock=$label variant=$variant error=budget spent (four minutes kept for the restore)"; continue } $n = if ($ca4) { 250 } else { $nb[$pk] } + if (-not $ca4 -and $lastMhs[$pk]) { $n = [math]::Max(20, [math]::Min(2000, [int][math]::Ceiling($stepSeconds * $lastMhs[$pk] * 1e6 / 16777216.0))) } $b = Bench $pk $n $variant if ($b.err) { "RESULT STEP card=$cardName pack=$pk lock=$label variant=$variant error=$($b.err) lock_note=$lockNote race=[$($b.race)]"; continue } $w = ReadWindow $b.t0.AddSeconds(8) $b.t1 @@ -266,7 +271,7 @@ function Step([string] $label, [string] $lockNote) { $lab = if ($ca4) { 'ca4-research' } else { 'efficiency' } $vfail = if ($ca4 -and $variant -ne 'base' -and ($b.served -eq 'base' -or $b.race -match 'variant_not_installed')) { ' variant_row=FAILED' } else { '' } "RESULT STEP card=$cardName pack=$pk lock=$label variant=$variant served=$($b.served) sparse_blocks=$($b.sparse)$vfail label=$lab sm_mhz=$sm mem_mhz=$mem watts=$watts watts_instant=$wInst watts_average=$wAvg temp_max=$tmax throttle=$thr mhs=$($b.mhs) mh_per_w=$eff fingerprint=$($b.fp) match=$match expected=$want check=$($b.check) batches=$n wall_s=$wall samples=$($w.Count) device=$($b.dev) lock_note=$lockNote alone=$alone race=[$($b.race)]" - if ($variant -eq 'base') { $script:rows += [pscustomobject]@{ pack = $pk; lock = $label; sm = $sm; watts = $watts; mhs = $b.mhs; eff = $eff; match = $match } } + if ($variant -eq 'base') { $script:rows += [pscustomobject]@{ pack = $pk; lock = $label; sm = $sm; watts = $watts; mhs = $b.mhs; eff = $eff; match = $match } }; if ($b.mhs) { $script:lastMhs[$pk] = $b.mhs } } } } try { @@ -293,7 +298,7 @@ try { foreach ($c in $locks) { foreach ($pk in $packOrder) { "RESULT STEP card=$cardName pack=$pk lock=$c error=no lock path (not elevated, no helper task)" } } } else { foreach ($c in $locks) { - if ((Get-Date) -gt $deadline) { "RESULT STEP card=$cardName pack=* lock=$c error=budget spent"; continue } + if ((Get-Date) -gt $deadline.AddMinutes(-4)) { "RESULT STEP card=$cardName pack=* lock=$c error=budget spent (four minutes kept for the restore)"; continue } $note = SetLock $c $lockState = "locked $c" if ($note -match 'no helper.log') { foreach ($pk in $packOrder) { "RESULT STEP card=$cardName pack=$pk lock=$c error=lock $note" }; "RESULT locks stopped at $c MHz: the helper gave no answer (a lock under the driver's floor hangs its nvidia-smi call); the remaining locks are skipped and the task is restarted for the reset"; RestartHelper | Out-Null; break } From 746099e3f23c87d2459c79c70c755be11913aaa9 Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Thu, 8 Oct 2026 02:56:18 +0000 Subject: [PATCH 4/4] PC 1 measurement pass: the step budget keeps four minutes of the cap for the restore and sizes each step from the last rate read; a probe dev line answered in helper.log counts as the helper up when its heartbeat stays stale; the gate check pc1-step-budget-check.sh with the known-failed case (the third 5090 pass of 8 October, ended by its cap at the 300 MHz step with the card left locked) Co-Authored-By: Claude Fable 5.1 --- tools/ci/checks.txt | 1 + tools/ci/pc1-step-budget-check.sh | 49 +++++++++++++++++++++++++++++++ tools/ci/pre-push.sh | 1 + 3 files changed, 51 insertions(+) create mode 100755 tools/ci/pc1-step-budget-check.sh diff --git a/tools/ci/checks.txt b/tools/ci/checks.txt index af73c0303..cd30a58d2 100644 --- a/tools/ci/checks.txt +++ b/tools/ci/checks.txt @@ -23,6 +23,7 @@ no playbook quits, pauses or resumes the installed app no script writes into another worktree or walks Projects the signer is never piped into head bash bodies in PowerShell job scripts pass bash -n +the PC 1 measurement pass keeps four minutes of its cap for the restore and sizes each step from the last rate (known-failed first) run jobs test their fetched kit before use every Windows spawn of the app runs with a hidden console pinned guest programs match their manifest diff --git a/tools/ci/pc1-step-budget-check.sh b/tools/ci/pc1-step-budget-check.sh new file mode 100755 index 000000000..e89436f99 --- /dev/null +++ b/tools/ci/pc1-step-budget-check.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +# The PC 1 measurement scripts' step budget (8 October 2026, 02:4x UTC, the Counter ASIC coordinator's order): the third 5090 pass sized +# every step's batch count from the unlocked rate, so the 500 MHz step ran 155 s instead of 60, the 45 min cap killed the script during +# the 300 MHz step, its finally block never ran and the card sat at a 400 MHz lock for four minutes until a restore job. Two rules on +# tools/ca3-v4-amend/pc1-v4-efficiency.ps1, checked here: (1) a step is started only when it ends before the cap less a four-minute reserve +# (`$deadline.AddMinutes(-4)` guards every step and every lock), so the clocks reset and the drift check run inside the cap; (2) the +# batch count per step follows the last rate read for the pack (`$lastMhs`), so a 60 s step stays 60 s as the rate falls. The self-test is +# the known-failed case: a grid whose steps lengthen past the cap under the old rule (the batch count fixed, the deadline alone) ends on +# the cap with no restore; under the new rule it ends with the restore run. Both halves run in the gate. +# bash tools/ci/pc1-step-budget-check.sh [--self-test] +set -euo pipefail +cd "$(dirname "$0")/../.." +# simulate(reserve_s, follow_rate): seconds at which the restore runs, or "cap" when the cap (2700 s) kills the script first. The grid is +# the third pass's: 2 packs x 9 locks; +# the unlocked rate 137 MH/s, each lock's rate following the clock below the knee (121 MH/s at 1,100 down to 32 at 300, as measured); +# a step's seconds = 60 x (the rate its batch count was sized from / the step's rate) + 15 s of build and settle, the restore 30 s. +simulate() { + local reserve="$1" follow="$2" cap=2700 t=120 rate=137000 sized=137000 lock + for lock in 1100 1000 900 800 700 600 500 400 300; do + rate=$(( 137000 * lock / 1300 )) # below the knee the rate follows the clock (the measured 121 MH/s at 1,100, 42.6 at 400) + [ "$follow" = 1 ] && sized=$rate + local step=$(( 2 * (60 * sized / rate + 15) )) # 60 s x (the sized rate's batch count) at the step's rate, 15 s of build and settle, two packs + # the guard is a clock check before the step (the script cannot know the step's length): the step starts when the clock is under + # the cap less the reserve, and the cap kills the script when the step overruns it + if [ $t -gt $(( cap - reserve )) ]; then break; fi + t=$(( t + step )) + [ $t -gt $cap ] && { echo cap; return; } + done + t=$(( t + 30 )) + if [ $t -gt $cap ]; then echo cap; else echo "$t"; fi +} +if [ "${1:-}" = "--self-test" ]; then + old=$(simulate 0 0); new=$(simulate 240 1) + [ "$old" = cap ] || { echo "self-test FAILED: the old rule (no reserve, the batch count fixed) should end on the cap, got $old"; exit 1; } + case "$new" in cap) echo "self-test FAILED: the new rule should end with the restore inside the cap"; exit 1 ;; esac + [ "$new" -le 2700 ] || { echo "self-test FAILED: the restore at $new s is past the cap"; exit 1; } + echo "self-test passed: the old rule ends on the cap with no restore; the new rule ends with the restore at $new s of 2700" + exit 0 +fi +f=tools/ca3-v4-amend/pc1-v4-efficiency.ps1 +[ -f "$f" ] || { echo "pc1-step-budget: $f is missing"; exit 1; } +bad=0 +n=$(grep -c 'deadline.AddMinutes(-4)' "$f" || true) +[ "$n" -ge 2 ] || { echo "pc1-step-budget: $f guards fewer than two places with the four-minute reserve (\$deadline.AddMinutes(-4): the step loop and the lock loop)"; bad=1; } +grep -q 'lastMhs\[\$pk\] \* 1e6' "$f" || { echo "pc1-step-budget: $f does not size the batch count from the last rate read (\$lastMhs)"; bad=1; } +grep -q 'script:lastMhs\[\$pk\] = \$b.mhs' "$f" || { echo "pc1-step-budget: $f never records the last rate per pack"; bad=1; } +if grep -vE '^\s*#' "$f" | grep -qE 'if \(\(Get-Date\) -gt \$deadline\)'; then echo "pc1-step-budget: $f still guards a step with the bare deadline (no reserve for the restore)"; bad=1; fi +[ $bad = 0 ] && echo "pc1-step-budget: the efficiency pass keeps four minutes for its restore and sizes each step from the last rate" +exit $bad diff --git a/tools/ci/pre-push.sh b/tools/ci/pre-push.sh index 554d31288..844ccb1f0 100755 --- a/tools/ci/pre-push.sh +++ b/tools/ci/pre-push.sh @@ -108,6 +108,7 @@ tree_checks() { run "no script writes into another worktree or walks Projects" bash -c 'bash tools/ci/no-foreign-tree-writes.sh --self-test && bash tools/ci/no-foreign-tree-writes.sh' run "the signer is never piped into head" bash tools/ci/signer-pipe-check.sh run "bash bodies in PowerShell job scripts pass bash -n" bash -c 'bash tools/ci/bash-body-check.sh --self-test && bash tools/ci/bash-body-check.sh' + run "the PC 1 measurement pass keeps four minutes of its cap for the restore and sizes each step from the last rate (known-failed first)" bash -c 'bash tools/ci/pc1-step-budget-check.sh --self-test && bash tools/ci/pc1-step-budget-check.sh' run "run jobs test their fetched kit before use" bash -c 'bash tools/ci/kit-path-check.sh --self-test && bash tools/ci/kit-path-check.sh' run "every Windows spawn of the app runs with a hidden console" bash -c 'node tools/ci/windows-spawn-check.mjs --self-test && node tools/ci/windows-spawn-check.mjs' run "pinned guest programs match their manifest" bash tools/ci/pinned-guests-check.sh