Merge branch 'ca3-pc1-amd' into ca3-coord

This commit is contained in:
igneum-labs 2026-10-06 17:23:56 +00:00
commit 9764820cb2
2 changed files with 96 additions and 6 deletions

View file

@ -40,7 +40,8 @@ The fetch lands at `<jobs>\fetch-ca3-pc1-amd-20261006\{bin,packs,src,SHA256SUMS}
| 0b (first in the queue after "Ember closed") | `pc1-amd-reset.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-reset-20261006 --script tools/ca3-pc1-amd/pc1-amd-reset.ps1 --timeout-minutes 5 --title "CA3 PC 1: 9070 XT ADLX back to factory, identities read" --deploy` | about 1 min | beside the miners, no card switch | the 9070 XT's ADLX tuning state after Ember run 6 (`gmax 0 plimit 0 factory 0`): `RESULT amd_state before gmax= plimit= factory=`, the factory reset as the Ember playbook did it (ember-tune ca990c2: `igneum-gpu-telemetry --card <ordinal> --reset`, the helper that answers `--tune`: the installed one first, else the newest amd-kit copy, which one printed), `RESULT amd_state after ...`, FAILED unless the after line reads factory 1; then READ ONLY the identities question of the 15:56Z restore: every gfx1201 settings.json entry (`RESULT settings_entry key= enabled= identities=`) and the app's live card list (`RESULT state_card key= identities= state= mhs_now= watts=`), `RESULT identities_answer live_key= identities=`; no POST of identities (the coordinator's call after the read) |
| 1b (the watts re-run, LAST in the queue) | `pc1-amd-watts.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-watts-20261006 --script tools/ca3-pc1-amd/pc1-amd-watts.ps1 --timeout-minutes 20 --title "CA3 PC 1: watts on the 9070 XT (app control + sh256x27 alone)" --deploy` | about 5 min | the control row with the card ON in the app; the candidate row with the 9070 XT ALONE | the two `watts= uj=` cells job 1 left owed, taken the way main trusts after Ember run 6 (the app's path: engine telemetry 363 of 363 nonzero, /api/state 456 of 456; a direct helper call alone is not trusted): (1) the CONTROL row with the card ON in the app mining class v3, `/api/state` polled at 1 Hz for 90 s (`RESULT APPROW class=v3 mhs_wall= watts_mean= watts_min= watts_max= samples= uj=`; the app's watts come from its own helper at -l 5, so they move every 5 s: `distinct_watts=` says how many values), the helper sampler running beside over the same 90 s (`RESULT sampler_vs_app helper_mean= app_mean= ratio=`); (2) the CANDIDATE row (sh256x27, the card alone through the kit worker, which /api/state cannot see) with the sampler as its only source and the ratio as its calibration (`RESULT LADDER ... watts_source=adlx calibration_ratio=`); a ratio outside 0.95 to 1.05 prints the candidate's watts as owed with the reason. The sampler is proven on the 12 idle seconds first (`RESULT sampler_raw` x3, `RESULT sampler_idle lines= lines_9070_with_watts=`); without a 9070 XT watts line no row is taken (`RESULT watts error=<why>`, status failed). About 5 min: 12 s proof, 90 s app window, the switch, about 90 s of bench, the restore |
| G2 (job 2's slot, after "Ember closed") | `pc1-amd-g2.ps1` | its own small kit first: `tools/ca3-pc1-amd/make-g2-kit.sh "$TMPDIR/igneum-ca3-pc1-amd-g2-kit.zip"` (rebuilt 6 October 16:4x UTC from the merged tree with the generator-4 packs and the merged packfile.h: sha256 `a16165483cbef9c9001897e2e965b95051c4e683940e0dbc9bded002ed0a0e7e`, 198,597 bytes, 35 files; worker exe `7dc3b1ee…`; the 16:2x build `f4c029c7…` carried the generator-3 copies and is superseded), then `packaging/ota/publish-jobs.sh add --kind fetch --target ae432dc7 --id fetch-ca3-pc1-amd-g2-20261006 --file "$TMPDIR/igneum-ca3-pc1-amd-g2-kit.zip" --dir jobs --extract --title "CA3 PC 1 G2 kit" --deploy`, then `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-g2-20261006 --script tools/ca3-pc1-amd/pc1-amd-g2.ps1 --timeout-minutes 10 --title "CA3 PC 1: gate G2 on the 9070 XT" --deploy` | about 2 min (two serve-mode jobs of 1,024 nonces; the Apple OpenCL dry run took 2.6 s a pack) | beside the miners (a correctness gate) | the "RX 9070 XT" cell of G2 in `docs/plans/counter-asic-3-gate/hash-gates.md` and the AMD line of G2 in status section 5: `RESULT g2 <pack> found <n> of 1024 distinct=<d> sha256 <digest> file <path> exit=<code>` (the hash lane's form) plus `RESULT G2 pack= found= distinct= digest= digest_match=yes|no`; the found lines go to `g2-<pack>.found` in the job folder, never to stdout; the Mac re-check is `tools/ca3-v4/g2-recheck.sh proto-cuda/packs-ca3-v4/<pack> --digest <hex>` (a digest match is 1,024 of 1,024), or `--file` after `publish-jobs.sh add --kind collect --target ae432dc7 --glob "app/jobs/run-ca3-pc1-amd-g2-20261006/g2-*.found"`. Packs: `packs-ca3-v4/mx8-devnet-epoch0` (control, class v3, id 73bcbfe8ccf988f1) and `packs-ca3-v4/v4-devnet-epoch0` (the candidate with the era at the devnet epoch-0 chain seeds; since the program-id fix 7c22d0d generator 4, class "v4", id c120d7963abdcd96, kernels and vectors byte-identical), NOT the first kit's `sh256x27`: that one is the genesis string-seed pack (`IGNEUM_SEED_BYTES_HEX` of 14 bytes) and the worker's job protocol takes only a 64-hex epoch seed, so it cannot be served (the script refuses such a pack with a RESULT line instead of a malformed job). The job line's class token is the pack's own `IGNEUM_PROGRAM_CLASS` (`class=v3` for the control, `class=v4` for the candidate), as `pc2-v4-gates.ps1` does since ca61dec: the worker refuses a token that disagrees with the pack (Mac check 16:41Z: `class=v3` on the v4 pack found 0, the known-bad case). Expected digests (the verifier through g2-recheck.sh on the Mac, equal to the kit worker's serve mode on Apple OpenCL at 16:21Z on the generator-3 copies and again at 16:41Z on the generator-4 packs through the merged host.c and packfile.h with `class=v4`, 1,024 of 1,024 every time; UNCHANGED by the re-export, as the byte-identical kernels require): mx8 `2a1824a2e0834287cf53b33f84cb7322014c85efa9788bece574e4e0730940bd`, v4 `435b976a4de57c5a26c8bada8b3b9e003504687c790d4b856bc56619d3aabd18`; the script carries them and prints `digest_match` itself |
| 2 (run b) | `pc1-amd-family.ps1` | its own kit first: `tools/ca3-pc1-amd/make-family-kit.sh "$TMPDIR/igneum-ca3-pc1-amd-family-kit.zip"` (built 6 October 18:0x UTC: sha256 `c8337e74af5f589d651603eddd3561700219bb5077f531a600a21719bb87ef58`; the probe exe `e7ad93a4d5b4d977…`), then `packaging/ota/publish-jobs.sh add --kind fetch --target ae432dc7 --id fetch-ca3-pc1-amd-family-20261006 --file "$TMPDIR/igneum-ca3-pc1-amd-family-kit.zip" --dir jobs --extract --title "CA3 PC 1 family kit" --deploy`, then `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-family-20261006-b --script tools/ca3-pc1-amd/pc1-amd-family.ps1 --timeout-minutes 15 --title "CA3 PC 1: family step costs on the 9070 XT (run b, by name)" --deploy` | about 3 min (3 runs on the 9070 XT by name, then 3 each on the older-platform duplicate and the gfx1036 by ordinal; builds dominate) | beside the miners (ratios; every row says `card_state=`) | the "RX 9070 XT" column of the item 6 table (section 3: `RESULT FAMILYBEST name=<f> ratio=<r> exact= path=` per family, `RESULT FAMILY ... variant=` for the form each took: `shfla_bperm` = `ds_bpermute_b32`, the one number that could move R3; `shflx_swz` / `shflx_bperm`; `perm_amd` = `v_perm_b32` through `amd_perm` or `perm_c` emulated; `bfe_amd`; `dot4_amd` = the 5 October sudot4 row re-measured; `mm8_gfx12` / `mm8_gfx11` = the WMMA builtins, exact=unverified); section 7 row "item 6: the 9070 XT step costs" |
| 2 (run e, the 9070 XT alone) | `pc1-amd-family.ps1` | the family kit of run b is on the PC (probe exe unchanged); publish only `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-family-20261006-e --script tools/ca3-pc1-amd/pc1-amd-family.ps1 --timeout-minutes 20 --title "CA3 PC 1: family step costs on the 9070 XT (run e, the card alone)" --deploy` | about 5 min (the switch up to 150 s, 3 runs alone, the restore, then the gfx1036 and old-platform columns beside the miners) | the 9070 XT ALONE for its three runs (job 1's path: every entry's key forms, process-list confirmation, each entry restored with its own flag and identities in finally; 5090 and 4070 keep mining); the other AMD columns beside the miners | run d (17:17Z) showed the dependent-chain ratio does not survive the card's own miner (alu 226 then 195 G steps/s; ratios 5.9 to 11.8x then 0.17 to 1.3x), so the 9070 XT column is taken alone as the Mac's and the 5090's were; rows carry `card_state=alone` (or `loaded` with `UNCONFIRMED` printed when the worker did not go); mm8 stays exact=unverified (the gfx12 WMMA iu8 16x16x16 fragment layout is in no source at hand; a guessed CPU layout would turn a wrong guess into exact=no) |
| 2 (run b, superseded by run e) | `pc1-amd-family.ps1` | its own kit first: `tools/ca3-pc1-amd/make-family-kit.sh "$TMPDIR/igneum-ca3-pc1-amd-family-kit.zip"` (built 6 October 18:0x UTC: sha256 `c8337e74af5f589d651603eddd3561700219bb5077f531a600a21719bb87ef58`; the probe exe `e7ad93a4d5b4d977…`), then `packaging/ota/publish-jobs.sh add --kind fetch --target ae432dc7 --id fetch-ca3-pc1-amd-family-20261006 --file "$TMPDIR/igneum-ca3-pc1-amd-family-kit.zip" --dir jobs --extract --title "CA3 PC 1 family kit" --deploy`, then `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-family-20261006-b --script tools/ca3-pc1-amd/pc1-amd-family.ps1 --timeout-minutes 15 --title "CA3 PC 1: family step costs on the 9070 XT (run b, by name)" --deploy` | about 3 min (3 runs on the 9070 XT by name, then 3 each on the older-platform duplicate and the gfx1036 by ordinal; builds dominate) | beside the miners (ratios; every row says `card_state=`) | the "RX 9070 XT" column of the item 6 table (section 3: `RESULT FAMILYBEST name=<f> ratio=<r> exact= path=` per family, `RESULT FAMILY ... variant=` for the form each took: `shfla_bperm` = `ds_bpermute_b32`, the one number that could move R3; `shflx_swz` / `shflx_bperm`; `perm_amd` = `v_perm_b32` through `amd_perm` or `perm_c` emulated; `bfe_amd`; `dot4_amd` = the 5 October sudot4 row re-measured; `mm8_gfx12` / `mm8_gfx11` = the WMMA builtins, exact=unverified); section 7 row "item 6: the 9070 XT step costs" |
| 3 | `pc1-amd-derive.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-derive-20261006 --script tools/ca3-pc1-amd/pc1-amd-derive.ps1 --timeout-minutes 15 --title "CA3 PC 1: dr736 on the 9070 XT" --deploy` | about 4 min (3 packs x a 60-dispatch pass and a 3-dispatch pass) | beside the miners (build, compile and bit-exact rows; the rate as a ratio to mx8 in the same job) | the item 2 table's 9070 XT cells (section 3: `RESULT DERIVE pack=dr736-genesis build_ms= build_ms_cached= build_ms_over_mx8= dataset_ms= fingerprint= match= mhs= ratio_to_mx8=`): the OpenCL compile cost of the derivation program against mx8's (the NVRTC +1.1 s finding on AMD), the 1 GiB daily build against mx8's 72 to 77 ms (5 October), bit-exactness on the AMD vendor; section 7 row "item 2: the 9070 XT rows" |
| 4 (optional, confirmed by main) | `pc1-4070-shadow.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-4070-shadow-20261006 --script tools/ca3-pc1-amd/pc1-4070-shadow.ps1 --timeout-minutes 30 --title "CA3 PC 1: item 8 ladder on the RTX 4070" --deploy` | about 11 min (7 benches of 100 to 200 dispatches at an expected 0.4 to 1 s each, approximate: no 4070 row exists yet; NVRTC per pack; the card switch) | 4070 ALONE (its CUDA worker stopped; 5090 and 9070 XT keep mining) | the "small NVIDIA card binds near 100,000" row of item 8 (section 3, consequences per tier at N = 100,000; section 7 "the 4060-class rows"): `RESULT LADDER pack=<p> ops=<N> mhs= watts= uj= sm_mhz=` with nvidia-smi at 1 Hz on that index; G1 fingerprints on a second NVIDIA card |

View file

@ -1,4 +1,4 @@
# Counter ASIC 3.0, PC 1 AMD job 2 (6 October 2026, run b): item 6's step cost of every reserve candidate family of spec
# Counter ASIC 3.0, PC 1 AMD job 2 (6 October 2026, run e: the 9070 XT ALONE): item 6's step cost of every reserve candidate family of spec
# 1.13.2 on PC 1's RX 9070 XT (machine ae432dc7, gfx1201), docs/plans/counter-asic-3-reserve.md, status file section
# 3 "Item 6" (the OWED AMD column). Run a (run-ca3-pc1-amd-family-20261006, 150 s, exit 0) measured ordinal 0, PC 1's
# integrated gfx1036 (one CU: alu 40.59 G steps/s against the 9070 XT's expected 1,000 to 2,000): the device list parse
@ -7,8 +7,15 @@
# newest AMD platform by driver version, the kit worker's dedup rule; `RESULT device_choice name= index= platform= driver=
# cus=`), prints the device's name, CUs and platform on every RESULT line, and refuses with `RESULT error` when no
# gfx1201 is listed; the older-platform duplicate and the gfx1036 run after it by explicit ordinal, as their own labelled
# columns. Published as a plain signed `run` job (NOT --stop-miners) and run BESIDE THE MINERS: a dependent-chain ratio
# survives a shared card; no card is switched; every line says loaded or quiet. The probe is the family kit's
# columns. Run d (17:17Z, the card by name, every variant built) showed a dependent-chain ratio does NOT survive the
# card's own miner: the alu chain read 226 then 195 G steps/s and the ratios swung from 5.9 to 11.8x to 0.17 to 1.3x
# between runs (the loaded card's scheduler, not the ops), while the Mac and 5090 columns were taken with the card alone.
# Run e: the 9070 XT is switched OFF in the installed app for its three runs (job 1's path: every key form of every
# settings.json gfx1201 entry through POST api/cards, quiet confirmed by the process list, the opencl worker carrying
# the card's --device index gone), restored in finally with each entry's own enabled flag and identities; the 5090 and
# the 4070 keep mining (a plain signed `run` job, NOT --stop-miners). The gfx1036 and the old-platform columns run
# AFTER the restore, beside the miners, as they are not the card under test. mm8 stays exact=unverified: the gfx12 WMMA
# iu8 16x16x16 fragment layout is in no source at hand, and a guessed CPU layout would turn a wrong guess into exact=no. The probe is the family kit's
# family-probe-cl.exe (proto-opencl/family-probe.c of branch ca3-pc1-amd, cross-compiled with mingw, OpenCL.dll at run
# time; the Mac ran the same source bit-exact on Apple OpenCL), three runs per device, each best of 3 with a fresh seed
# per repetition, device event time, bit-exact against the CPU reference on two whole 32-lane groups. Every family is
@ -46,6 +53,56 @@ $cardState = if ($amdLoaded) { 'loaded' } else { 'quiet' }
"RESULT workers_before $(Stamp) $($w -join ' ')"
"RESULT context card_state=$(if ($amdLoaded) { 'LOADED (an igneum-worker-opencl process mines on an AMD card: absolutes are shared-card figures, ratios stand)' } else { 'quiet (no igneum-worker-opencl process)' })"
# ---- the installed app and the card's settings.json entries (READ ONLY), for the card-alone runs ----
$inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1
$appDir = if ($env:IGNEUM_APP_DIR) { $env:IGNEUM_APP_DIR } else { Join-Path $env:LOCALAPPDATA 'igneum\app' }
$urlFile = Join-Path $appDir 'app.url'
$base = $null
if (Test-Path $urlFile) { $base = (Get-Content -LiteralPath $urlFile -Raw).Trim().TrimEnd('/') }
"RESULT app install=$inst app_dir=$appDir url_present=$([bool]$base)"
# the 9070 XT's OpenCL device index as the APP numbers it (the installed worker's --list; the probe's own list below
# numbers devices differently), for the process-list check of its worker
$dev = $null
if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) {
$wl = @(& (Join-Path $inst 'igneum-worker-opencl.exe') --list 2>&1 | ForEach-Object { "$_" })
foreach ($l in $wl) { if ($l -match '^\s*\[(\d+)\].*gfx1201' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } }
}
"RESULT app_device $(if ($null -ne $dev) { $dev } else { 'unknown (no installed worker list: the quiet check falls back to any opencl worker)' })"
$entries = @()
try {
$sj = Get-Content -LiteralPath (Join-Path $appDir 'settings.json') -Raw | ConvertFrom-Json
foreach ($prop in $sj.cards.PSObject.Properties) {
if ($prop.Name -like 'amd:*' -and $prop.Name -match 'gfx1201') {
$parts = $prop.Name -split ':'
$forms = @()
if ($parts.Count -ge 3) { $forms += ($parts[0] + ':' + $parts[1]); $forms += ($parts[0] + ':' + $parts[2]) }
$ident = 1; if ($prop.Value.identities) { $ident = [int] $prop.Value.identities }
$entries += [pscustomobject]@{ key = $prop.Name; forms = $forms; enabled = [bool] $prop.Value.enabled; identities = $ident }
"RESULT card settings_key=$($prop.Name) enabled=$([bool] $prop.Value.enabled) identities=$ident derived_forms=[$($forms -join ' | ')]"
}
}
} catch { "RESULT settings_read_failed $($_.Exception.Message)" }
if ($entries.Count -eq 0) { "RESULT card none in settings.json matching amd:*gfx1201*: no switch possible; the 9070 XT rows will be loaded-card figures" }
# off: every form of every entry; restore: the derived forms first, then each key as written with ITS OWN settings
function PostCards([bool] $enabled) {
if (-not $base) { "RESULT cards no app.url: nothing posted"; return }
foreach ($pass in @('derived', 'written')) {
foreach ($e in $entries) {
$keys = if ($pass -eq 'derived') { $e.forms } else { @($e.key) }
$on = if ($enabled) { $e.enabled } else { $false }
foreach ($k in $keys) {
$body = @{ cards = @(@{ key = $k; enabled = $on; identities = $e.identities }) } | ConvertTo-Json -Depth 5
try { Invoke-RestMethod -Uri "$base/api/cards" -Method POST -Body $body -ContentType 'application/json' -TimeoutSec 10 | Out-Null; "RESULT cards key=$k enabled=$on identities=$($e.identities) posted (from entry $($e.key))" } catch { "RESULT cards key=$k enabled=$on error=$($_.Exception.Message)" }
}
}
}
}
function CardWorkers {
$procs = @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe'" -ErrorAction SilentlyContinue)
if ($null -ne $dev) { $procs = @($procs | Where-Object { $_.CommandLine -match "--device\s+$dev(\s|$)" }) }
@($procs | ForEach-Object { $_.ProcessId })
}
# the probe's own device list: the 9070 XT by name first (the probe picks the newest platform itself), then the
# older-platform duplicate and the gfx1036 by explicit ordinal as their own columns
$list = @(& $probe --list 2>&1 | ForEach-Object { "$_" })
@ -82,7 +139,39 @@ function RunProbe([string] $label, [string[]] $probeArgs, [int] $r) {
if ($rc -ne 0) { "RESULT run=$r dev=$label error=probe exit $rc" }
$script:runs++
}
for ($r = 1; $r -le 3; $r++) { RunProbe '9070xt' @('--device-name', 'gfx1201') $r; Start-Sleep -Seconds 2 }
# ---- the 9070 XT alone: off in the app, confirmed quiet, three runs, restored whatever happens ----
$switched = $false
$cardAlone = $false
try {
if ($entries.Count -gt 0 -and $base) {
$before = @(CardWorkers)
"RESULT card_workers_before pids=[$($before -join ' ')]"
if ($before.Count -eq 0) { "RESULT card already quiet before the switch (no opencl worker for the card)"; $cardAlone = $true }
else {
PostCards $false; $switched = $true
$t = 0
while ($t -lt 150) { Start-Sleep -Seconds 5; $t += 5; if ((@(CardWorkers)).Count -eq 0) { break } }
$left = @(CardWorkers)
if ($left.Count -eq 0) { "RESULT card $(Stamp) quiet after $t s: the card's igneum-worker-opencl process is gone (the card to itself)"; $cardAlone = $true }
else { "RESULT card $(Stamp) UNCONFIRMED after $t s: opencl worker pids [$($left -join ' ')] still run; the 9070 XT rows below are LOADED-card figures (run d's class)" }
Start-Sleep -Seconds 8
}
} else { "RESULT card not switched (no entry or no app.url): the 9070 XT rows below carry whatever load the card has" }
$cardState = if ($cardAlone) { 'alone' } else { 'loaded' }
"RESULT workers_during $(Stamp) $((Workers) -join ' ')"
for ($r = 1; $r -le 3; $r++) { RunProbe '9070xt' @('--device-name', 'gfx1201') $r; Start-Sleep -Seconds 2 }
} finally {
if ($switched) {
PostCards $true
"RESULT card restore posted: each settings.json entry with its own enabled flag and identities"
$t = 0; $back = @()
$anyEnabled = ($entries | Where-Object { $_.enabled }).Count -gt 0
while ($t -lt 90 -and $anyEnabled) { Start-Sleep -Seconds 5; $t += 5; $back = @(CardWorkers); if ($back.Count -gt 0) { break } }
"RESULT card_workers_after $(Stamp) pids=[$($back -join ' ')] after $t s $(if ($back.Count -gt 0) { '(the card mines again)' } elseif ($anyEnabled) { '(NOT back yet: check the app)' } else { '(no entry was enabled before this job)' })"
}
}
# ---- the other AMD columns beside the miners (not the card under test) ----
$cardState = if ((@(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe'" -ErrorAction SilentlyContinue)).Count -gt 0) { 'loaded' } else { 'quiet' }
foreach ($d in $byOrdinal) {
$label = if ($d.name -match 'gfx1201') { 'gfx1201-old-platform' } elseif ($d.name -match 'gfx1036') { 'gfx1036' } else { 'amd-' + $d.idx }
for ($r = 1; $r -le 3; $r++) { RunProbe $label @('--device', "$($d.idx)") $r; Start-Sleep -Seconds 2 }
@ -90,6 +179,6 @@ foreach ($d in $byOrdinal) {
"RESULT workers_after $(Stamp) $((Workers) -join ' ')"
"RESULT end $(Stamp)"
$status = if ($mainRows -gt 0) { 'done' } elseif ($rowsTotal -gt 0) { 'partial' } else { 'failed' }
Summary $status @{ runs = $runs; family_rows = $rowsTotal; rows_9070xt = $mainRows; exact_rows = $exactRows; failed_builds = $failedBuilds; familybest_rows = $built; probe_errors = $probeErrors; card_state = $cardState }
Summary $status @{ runs = $runs; family_rows = $rowsTotal; rows_9070xt = $mainRows; card_alone_9070xt = $cardAlone; exact_rows = $exactRows; failed_builds = $failedBuilds; familybest_rows = $built; probe_errors = $probeErrors }
if ($status -eq 'failed') { exit 1 }
exit 0