From bff1bdf751fea6eff0cd7f0008e84a1c64c0f666 Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Thu, 13 Aug 2026 12:26:26 +0200 Subject: [PATCH 1/6] perf(miri): parallelize test artifacts Compile each profile once to preserve workspace feature unification, then run its test artifacts with bounded parallelism and longest-first scheduling. Avoid formatting-only macro test work under Miri while retaining normal syntax validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- Cargo.lock | 1 - crates/multitude_macros_impl/Cargo.toml | 3 - crates/multitude_macros_impl/src/lib.rs | 62 ++++++- .../anvil/checks/miri-race-coverage.just | 3 +- .../anvil/checks/miri-strict-provenance.just | 3 +- justfiles/anvil/checks/miri-tree-borrows.just | 3 +- justfiles/anvil/checks/miri.just | 151 +++++++++++++++++- 7 files changed, 209 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c832b629a..f0c3e56fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3008,7 +3008,6 @@ dependencies = [ name = "multitude_macros_impl" version = "0.1.1" dependencies = [ - "prettyplease 0.3.0", "proc-macro2", "quote", "syn 3.0.3", diff --git a/crates/multitude_macros_impl/Cargo.toml b/crates/multitude_macros_impl/Cargo.toml index b50d29861..643e126bd 100644 --- a/crates/multitude_macros_impl/Cargo.toml +++ b/crates/multitude_macros_impl/Cargo.toml @@ -34,9 +34,6 @@ proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true, features = ["full", "derive", "printing", "parsing", "extra-traits", "proc-macro", "clone-impls"] } -[dev-dependencies] -prettyplease = { workspace = true } - # >>> anvil-managed: anvil-lints [lints] workspace = true diff --git a/crates/multitude_macros_impl/src/lib.rs b/crates/multitude_macros_impl/src/lib.rs index b4899aebd..7876103a9 100644 --- a/crates/multitude_macros_impl/src/lib.rs +++ b/crates/multitude_macros_impl/src/lib.rs @@ -1523,14 +1523,64 @@ fn enum_tokens( #[cfg(test)] mod tests { + use std::ops::Deref; + use super::*; - fn expand(source: &str) -> String { + struct Generated(String); + + impl Generated { + fn new(value: &str) -> Self { + let mut compact = String::with_capacity(value.len()); + let mut in_string = false; + let mut escaped = false; + for ch in value.chars() { + if in_string { + compact.push(ch); + if escaped { + escaped = false; + } else if ch == '\\' { + escaped = true; + } else if ch == '"' { + in_string = false; + } + } else if ch == '"' { + in_string = true; + compact.push(ch); + } else if !ch.is_whitespace() { + compact.push(ch); + } + } + Self(compact) + } + + fn contains(&self, expected: &str) -> bool { + self.0.contains(expected) || self.0.contains(&Self::new(expected).0) + } + + fn match_count(&self, expected: &str) -> usize { + self.0.matches(&Self::new(expected).0).count() + } + } + + impl Deref for Generated { + type Target = str; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + fn expand(source: &str) -> Generated { let input: DeriveInput = syn::parse_str(source).unwrap(); let root: Path = parse_quote!(::multitude::de); let generated = super::expand(&input, &root).unwrap(); - let file: syn::File = syn::parse2(generated).unwrap(); - prettyplease::unparse(&file) + + #[cfg(not(miri))] + syn::parse2::(generated.clone()).unwrap(); + let rendered = generated.to_string(); + + Generated::new(&rendered) } #[test] @@ -1601,7 +1651,7 @@ mod tests { assert!(enumeration.contains("variant index 0 <= i < 2")); assert!(enumeration.contains("Variant2")); assert!(!enumeration.contains("Variant1,")); - assert!(compact_enumeration.contains("1u64=>{::core::result::Result::Ok(__MultitudeVariantForE::Variant2)")); + assert!(compact_enumeration.contains("1u64=>::core::result::Result::Ok(__MultitudeVariantForE::Variant2)")); assert!(!compact_enumeration.contains("2u64=>")); } @@ -1766,7 +1816,7 @@ mod tests { assert!(!variant.contains("T: ::multitude::de::DeserializeIn")); let compact: String = variant.split_whitespace().collect(); - assert_eq!(compact.matches("let_:()=__value;").count(), 3); + assert_eq!(variant.match_count("let _: () = __value;"), 3); let single_named_constructor = ["E::Single", "{", "value:__value", "}"].concat(); assert!(compact.contains(&single_named_constructor)); for constructor in [ @@ -1896,7 +1946,7 @@ mod tests { let shapes = expand("enum Shapes { New(u8), OneSkipped(#[serde(skip)] u8), Unit, Named { value: u8 } }"); let compact: String = shapes.split_whitespace().collect(); assert!(compact.contains("__MultitudeVariantForShapes::Variant0=>{let__value=__Serde::de::VariantAccess::newtype_variant_seed")); - assert!(compact.contains("__MultitudeVariantForShapes::Variant1=>{__Serde::de::VariantAccess::tuple_variant(__access,0usize,")); + assert!(compact.contains("__MultitudeVariantForShapes::Variant1=>__Serde::de::VariantAccess::tuple_variant(__access,0usize,")); assert!(shapes.contains("tuple_variant")); assert!(shapes.contains("struct_variant")); assert!(shapes.contains("unit_variant")); diff --git a/justfiles/anvil/checks/miri-race-coverage.just b/justfiles/anvil/checks/miri-race-coverage.just index da3945bdb..504d78a98 100644 --- a/justfiles/anvil/checks/miri-race-coverage.just +++ b/justfiles/anvil/checks/miri-race-coverage.just @@ -18,14 +18,13 @@ anvil-miri-race-coverage: anvil-miri-race-coverage-validate-prereqs $ErrorActionPreference = 'Stop' if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } - $pkg = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) $day = (Get-Date).Day $low = (2 * $day) - 1 $high = (2 * $day) + 1 $env:MIRIFLAGS = "-Zmiri-many-seeds=$low..$high $($env:MIRIFLAGS)".Trim() $env:RUSTFLAGS = "--cfg miri_race_coverage $($env:RUSTFLAGS)".Trim() Write-Host "anvil-miri-race-coverage: seed window $low..$high (day $day)" - & cargo '+{{ rust_nightly }}' miri test --all-features --tests @pkg + & "{{just_executable()}}" _anvil-miri-test if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install prerequisites for the `anvil-miri-race-coverage` recipe. diff --git a/justfiles/anvil/checks/miri-strict-provenance.just b/justfiles/anvil/checks/miri-strict-provenance.just index 14069df8e..890866ba4 100644 --- a/justfiles/anvil/checks/miri-strict-provenance.just +++ b/justfiles/anvil/checks/miri-strict-provenance.just @@ -11,10 +11,9 @@ anvil-miri-strict-provenance: anvil-miri-strict-provenance-validate-prereqs $ErrorActionPreference = 'Stop' if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } - $pkg = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) $env:MIRIFLAGS = "-Zmiri-strict-provenance $($env:MIRIFLAGS)".Trim() $env:RUSTFLAGS = "--cfg miri_strict_provenance $($env:RUSTFLAGS)".Trim() - & cargo '+{{ rust_nightly }}' miri test --all-features --tests @pkg + & "{{just_executable()}}" _anvil-miri-test if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Install prerequisites for the `anvil-miri-strict-provenance` recipe. diff --git a/justfiles/anvil/checks/miri-tree-borrows.just b/justfiles/anvil/checks/miri-tree-borrows.just index 86c2f5c60..97ae4e927 100644 --- a/justfiles/anvil/checks/miri-tree-borrows.just +++ b/justfiles/anvil/checks/miri-tree-borrows.just @@ -24,10 +24,9 @@ anvil-miri-tree-borrows: anvil-miri-tree-borrows-validate-prereqs $ErrorActionPreference = 'Stop' if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } - $pkg = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) $env:MIRIFLAGS = "-Zmiri-tree-borrows $($env:MIRIFLAGS)".Trim() $env:RUSTFLAGS = "--cfg miri_tree_borrows $($env:RUSTFLAGS)".Trim() - & cargo '+{{ rust_nightly }}' miri test --all-features --tests @pkg + & "{{just_executable()}}" _anvil-miri-test if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # The three nightly-miri profiles share the same toolchain prereqs diff --git a/justfiles/anvil/checks/miri.just b/justfiles/anvil/checks/miri.just index 883605f39..8852c3e08 100644 --- a/justfiles/anvil/checks/miri.just +++ b/justfiles/anvil/checks/miri.just @@ -10,6 +10,155 @@ # by the scheduled workflow, so the affected-tier default (--workspace) # applies. Skip guards are still included for local diff-scoped runs. +# Compile all selected packages together, then run their Miri test artifacts in +# parallel. The single Cargo invocation preserves workspace feature unification, +# while parallel artifact execution uses the runner cores that a normal +# `cargo miri test` invocation leaves idle. +# +# ANVIL_MIRI_JOBS overrides the automatically selected process count. The +# default reserves roughly 8 GiB per process and never exceeds five processes +# or half the logical processors, limiting pressure from Tree Borrows and +# many-seeds profiles on smaller hosted runners. +[script("pwsh")] +_anvil-miri-test: + $ErrorActionPreference = 'Stop' + if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } + + $packageArgs = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) + $logRoot = Join-Path ([IO.Path]::GetTempPath()) "anvil-miri-$PID-$([guid]::NewGuid())" + New-Item -ItemType Directory -Path $logRoot | Out-Null + try { + $artifactManifest = Join-Path $logRoot 'artifacts.jsonl' + $toolchain = '+{{ rust_nightly }}' + & cargo $toolchain miri test --all-features --tests --no-run --message-format=json-render-diagnostics @packageArgs 1> $artifactManifest + $buildExitCode = $LASTEXITCODE + + $metadata = & cargo metadata --no-deps --format-version 1 | ConvertFrom-Json + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $packageDirectories = @{} + foreach ($package in $metadata.packages) { + $packageDirectories[[string]$package.id] = Split-Path -Parent ([string]$package.manifest_path) + } + + $artifacts = [System.Collections.Generic.List[object]]::new() + $seenArtifacts = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + foreach ($line in Get-Content -LiteralPath $artifactManifest) { + if (-not $line.TrimStart().StartsWith('{')) { + [Console]::Error.WriteLine($line) + continue + } + $message = $line | ConvertFrom-Json -ErrorAction Stop + if ($message.reason -eq 'compiler-message' -and $message.message.rendered) { + [Console]::Error.Write($message.message.rendered) + } elseif ($message.reason -eq 'compiler-artifact' -and $message.executable) { + if ($seenArtifacts.Add([string]$message.executable)) { + $packageId = [string]$message.package_id + if (-not $packageDirectories.ContainsKey($packageId)) { + Write-Error "anvil miri: package metadata not found for artifact package '$packageId'" + exit 1 + } + $name = Split-Path -Leaf ([string]$message.executable) + $priority = 100 + # Start the consistently longest code-generation suites first + # so they do not extend the tail after short artifacts finish. + switch -Regex ($name) { + '^routerama_build-' { $priority = 0; break } + '^multitude_macros_impl-' { $priority = 1; break } + '^rest_over_grpc-' { $priority = 2; break } + '^internity_macros_impl-' { $priority = 3; break } + '^arena-' { $priority = 4; break } + '^enrich_err-' { $priority = 5; break } + '^routerama-' { $priority = 6; break } + '^basic-' { $priority = 7; break } + } + $artifacts.Add([pscustomobject]@{ + Path = [string]$message.executable + Name = $name + Priority = $priority + WorkingDirectory = $packageDirectories[$packageId] + }) + } + } + } + + if ($buildExitCode -ne 0) { exit $buildExitCode } + if ($artifacts.Count -eq 0) { + Write-Error 'anvil miri: Cargo produced no runnable test artifacts' + exit 1 + } + + $sysrootOutput = @(& cargo $toolchain miri setup --print-sysroot) + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $env:MIRI_SYSROOT = $sysrootOutput[-1] + $env:MIRI_BE_RUSTC = 'host' + $runner = & rustup which --toolchain '{{ rust_nightly }}' cargo-miri + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + + $jobs = 0 + if ($env:ANVIL_MIRI_JOBS) { + if (-not [int]::TryParse($env:ANVIL_MIRI_JOBS, [ref]$jobs) -or $jobs -lt 1) { + Write-Error "ANVIL_MIRI_JOBS must be a positive integer, got '$($env:ANVIL_MIRI_JOBS)'" + exit 1 + } + } else { + $processorJobs = [Math]::Max(1, [Math]::Floor([Environment]::ProcessorCount / 2)) + $availableBytes = [GC]::GetGCMemoryInfo().TotalAvailableMemoryBytes + $memoryJobs = [Math]::Max(1, [Math]::Floor($availableBytes / 8GB)) + $jobs = [Math]::Min(5, [Math]::Min($processorJobs, $memoryJobs)) + } + $jobs = [Math]::Min($jobs, $artifacts.Count) + Write-Host "anvil miri: running $($artifacts.Count) test artifacts with $jobs concurrent process(es)" + + $orderedArtifacts = @($artifacts | Sort-Object Priority, Name) + $work = for ($i = 0; $i -lt $orderedArtifacts.Count; $i++) { + [pscustomobject]@{ + Index = $i + Artifact = $orderedArtifacts[$i].Path + Name = $orderedArtifacts[$i].Name + WorkingDirectory = $orderedArtifacts[$i].WorkingDirectory + } + } + $results = @( + $work | ForEach-Object -Parallel { + $item = $_ + $log = Join-Path $using:logRoot "$($item.Index).log" + Write-Host "anvil miri: starting $($item.Name)" + Push-Location -LiteralPath $item.WorkingDirectory + try { + & $using:runner runner $item.Artifact *> $log + $exitCode = $LASTEXITCODE + } finally { + Pop-Location + } + Write-Host "anvil miri: completed $($item.Name) (exit $exitCode)" + [pscustomobject]@{ + Index = $item.Index + Name = $item.Name + ExitCode = $exitCode + Log = $log + } + } -ThrottleLimit $jobs + ) + + foreach ($result in $results | Sort-Object Index) { + if ($env:GITHUB_ACTIONS -eq 'true') { + Write-Host "::group::Miri artifact $($result.Name)" + } else { + Write-Host "`n=== Miri artifact $($result.Name) ===" + } + Get-Content -LiteralPath $result.Log | ForEach-Object { Write-Host $_ } + if ($env:GITHUB_ACTIONS -eq 'true') { Write-Host '::endgroup::' } + } + + $failed = @($results | Where-Object ExitCode -ne 0) + if ($failed.Count -ne 0) { + [Console]::Error.WriteLine("anvil miri: failed artifacts: $($failed.Name -join ', ')") + exit 1 + } + } finally { + Remove-Item -LiteralPath $logRoot -Recurse -Force -ErrorAction SilentlyContinue + } + # Run Miri tests for affected workspace packages. [script("pwsh")] anvil-miri: anvil-miri-validate-prereqs @@ -40,7 +189,7 @@ anvil-miri: anvil-miri-validate-prereqs # whose tests are all `#[cfg_attr(miri, ignore)]` -- the canonical # opt-out for build-tooling / CLI crates), so the old nextest # `--no-tests=pass` workaround is no longer needed. - & cargo '+{{ rust_nightly }}' miri test --all-features --tests @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) + & "{{just_executable()}}" _anvil-miri-test if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # --- pr-runtime-analysis members --- From f1352440fc52703f8b6442bb25fc00eee322f89c Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 14 Aug 2026 11:11:00 +0200 Subject: [PATCH 2/6] perf(miri): use all runner CPUs Select one concurrent test artifact per logical processor and log GC memory telemetry so scheduled runs can reveal whether memory pressure limits the CPU-based configuration. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- justfiles/anvil/checks/miri.just | 38 ++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/justfiles/anvil/checks/miri.just b/justfiles/anvil/checks/miri.just index 8852c3e08..512aa2f81 100644 --- a/justfiles/anvil/checks/miri.just +++ b/justfiles/anvil/checks/miri.just @@ -16,9 +16,12 @@ # `cargo miri test` invocation leaves idle. # # ANVIL_MIRI_JOBS overrides the automatically selected process count. The -# default reserves roughly 8 GiB per process and never exceeds five processes -# or half the logical processors, limiting pressure from Tree Borrows and -# many-seeds profiles on smaller hosted runners. +# default uses one process per logical processor. GC memory information is +# logged as telemetry but does not limit concurrency, allowing scheduled runs +# to reveal whether memory pressure makes the CPU-based setting unsuitable for +# a runner class. + +# Run selected Miri test artifacts with CPU-based parallelism. [script("pwsh")] _anvil-miri-test: $ErrorActionPreference = 'Stop' @@ -101,12 +104,16 @@ _anvil-miri-test: exit 1 } } else { - $processorJobs = [Math]::Max(1, [Math]::Floor([Environment]::ProcessorCount / 2)) - $availableBytes = [GC]::GetGCMemoryInfo().TotalAvailableMemoryBytes - $memoryJobs = [Math]::Max(1, [Math]::Floor($availableBytes / 8GB)) - $jobs = [Math]::Min(5, [Math]::Min($processorJobs, $memoryJobs)) + $jobs = [Environment]::ProcessorCount } $jobs = [Math]::Min($jobs, $artifacts.Count) + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + $memoryInfo = [GC]::GetGCMemoryInfo() + $gcAvailableGiB = [Math]::Round($memoryInfo.TotalAvailableMemoryBytes / 1GB, 1) + $memoryLoadGiB = [Math]::Round($memoryInfo.MemoryLoadBytes / 1GB, 1) + $highMemoryLoadGiB = [Math]::Round($memoryInfo.HighMemoryLoadThresholdBytes / 1GB, 1) + Write-Host "anvil miri: $([Environment]::ProcessorCount) logical processor(s); GC reports $gcAvailableGiB GiB available, $memoryLoadGiB GiB load, $highMemoryLoadGiB GiB high-load threshold" Write-Host "anvil miri: running $($artifacts.Count) test artifacts with $jobs concurrent process(es)" $orderedArtifacts = @($artifacts | Sort-Object Priority, Name) @@ -120,9 +127,22 @@ _anvil-miri-test: } $results = @( $work | ForEach-Object -Parallel { + function Get-MemoryTelemetry { + [GC]::Collect() + [GC]::WaitForPendingFinalizers() + $info = [GC]::GetGCMemoryInfo() + $capacityGiB = [Math]::Round($info.TotalAvailableMemoryBytes / 1GB, 1) + $loadGiB = [Math]::Round($info.MemoryLoadBytes / 1GB, 1) + $headroomGiB = [Math]::Round( + [Math]::Max([long]0, $info.TotalAvailableMemoryBytes - $info.MemoryLoadBytes) / 1GB, + 1 + ) + "GC load $loadGiB/$capacityGiB GiB, estimated headroom $headroomGiB GiB" + } + $item = $_ $log = Join-Path $using:logRoot "$($item.Index).log" - Write-Host "anvil miri: starting $($item.Name)" + Write-Host "anvil miri: starting $($item.Name) ($(Get-MemoryTelemetry))" Push-Location -LiteralPath $item.WorkingDirectory try { & $using:runner runner $item.Artifact *> $log @@ -130,7 +150,7 @@ _anvil-miri-test: } finally { Pop-Location } - Write-Host "anvil miri: completed $($item.Name) (exit $exitCode)" + Write-Host "anvil miri: completed $($item.Name) (exit $exitCode; $(Get-MemoryTelemetry))" [pscustomobject]@{ Index = $item.Index Name = $item.Name From fd281db850a389115aa1eeab62941d57f9f529d3 Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Tue, 25 Aug 2026 15:34:05 +0200 Subject: [PATCH 3/6] perf(miri): reduce resource-heavy test workloads Preserve native stress coverage while bounding Routerama depth and high-cardinality Arena tests under Miri. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- crates/multitude/tests/arena.rs | 70 +++++++++++++++++++++-------- crates/routerama/src/dyn_builder.rs | 7 ++- 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/crates/multitude/tests/arena.rs b/crates/multitude/tests/arena.rs index 386c36052..3c25a9bec 100644 --- a/crates/multitude/tests/arena.rs +++ b/crates/multitude/tests/arena.rs @@ -3205,6 +3205,9 @@ mod drop_slice_over_u16_max_succeeds { const TOO_LONG: usize = (u16::MAX as usize) + 1; + // These tests verify a runtime length boundary rather than memory safety. + // Native CI retains the full boundary coverage without Miri's per-element cost. + #[cfg_attr(miri, ignore)] #[test] fn try_alloc_slice_clone_drop_over_u16_succeeds() { let a = Arena::new(); @@ -3212,6 +3215,7 @@ mod drop_slice_over_u16_max_succeeds { assert_eq!(a.try_alloc_slice_clone(&v[..]).unwrap().len(), TOO_LONG); } + #[cfg_attr(miri, ignore)] #[test] fn try_alloc_slice_fill_with_drop_over_u16_succeeds() { let a = Arena::new(); @@ -3221,6 +3225,7 @@ mod drop_slice_over_u16_max_succeeds { ); } + #[cfg_attr(miri, ignore)] #[test] fn try_alloc_slice_fill_iter_drop_over_u16_succeeds() { let a = Arena::new(); @@ -3597,6 +3602,7 @@ mod alloc_slice_overflow_paths { // type lowers to a single capacity allocation plus a bulk // initializing loop — much cheaper than `(0..N).map(...).collect()` // which runs the closure N times. + #[cfg_attr(miri, ignore)] #[test] fn alloc_slice_clone_drop_over_u16_succeeds() { let v: std::vec::Vec = std::vec![D(0); u16::MAX as usize + 1]; @@ -3605,6 +3611,7 @@ mod alloc_slice_overflow_paths { assert_eq!(s.len(), u16::MAX as usize + 1); } + #[cfg_attr(miri, ignore)] #[test] fn alloc_slice_fill_with_drop_over_u16_succeeds() { let arena = Arena::new(); @@ -3612,6 +3619,7 @@ mod alloc_slice_overflow_paths { assert_eq!(s.len(), u16::MAX as usize + 1); } + #[cfg_attr(miri, ignore)] #[test] fn alloc_slice_fill_iter_drop_over_u16_succeeds() { let arena = Arena::new(); @@ -3694,6 +3702,22 @@ mod oversized_paths_coverage { fn drop(&mut self) {} } + #[cfg(miri)] + const OVERSIZED_DROP_LEN: usize = 513; + #[cfg(not(miri))] + const OVERSIZED_DROP_LEN: usize = 3000; + + fn oversized_drop_arena() -> Arena { + #[cfg(miri)] + { + Arena::builder().max_normal_alloc(4 * 1024).build() + } + #[cfg(not(miri))] + { + Arena::new() + } + } + // 24 KiB single value with Drop ⇒ oversized-local value arm // (`alloc_value.rs` 433-436). #[derive(Clone)] @@ -3717,36 +3741,40 @@ mod oversized_paths_coverage { use core::sync::atomic::{AtomicUsize, Ordering}; let counter = AtomicUsize::new(0); { - let arena = Arena::new(); - let out = arena.alloc_slice_fill_with(3000, |_| CountedDrop(&counter)); - assert_eq!(out.len(), 3000); + let arena = oversized_drop_arena(); + let out = arena.alloc_slice_fill_with(OVERSIZED_DROP_LEN, |_| CountedDrop(&counter)); + assert_eq!(out.len(), OVERSIZED_DROP_LEN); assert_eq!(counter.load(Ordering::SeqCst), 0, "no drops before teardown"); } - assert_eq!(counter.load(Ordering::SeqCst), 3000, "every element dropped at arena teardown"); + assert_eq!( + counter.load(Ordering::SeqCst), + OVERSIZED_DROP_LEN, + "every element dropped at arena teardown" + ); } #[test] fn alloc_slice_clone_oversized_drop() { - let arena = Arena::new(); - let src: Vec = (0..3000).map(DropU64).collect(); + let arena = oversized_drop_arena(); + let src: Vec = (0..OVERSIZED_DROP_LEN).map(|i| DropU64(i as u64)).collect(); let out = arena.alloc_slice_clone(&src); - assert_eq!(out.len(), 3000); - assert_eq!(out[2999].0, 2999); + assert_eq!(out.len(), OVERSIZED_DROP_LEN); + assert_eq!(out[OVERSIZED_DROP_LEN - 1].0, (OVERSIZED_DROP_LEN - 1) as u64); } #[test] fn alloc_slice_fill_with_oversized_drop() { - let arena = Arena::new(); - let out = arena.alloc_slice_fill_with(3000, |i| DropU64(i as u64)); - assert_eq!(out.len(), 3000); - assert_eq!(out[2999].0, 2999); + let arena = oversized_drop_arena(); + let out = arena.alloc_slice_fill_with(OVERSIZED_DROP_LEN, |i| DropU64(i as u64)); + assert_eq!(out.len(), OVERSIZED_DROP_LEN); + assert_eq!(out[OVERSIZED_DROP_LEN - 1].0, (OVERSIZED_DROP_LEN - 1) as u64); } #[test] fn alloc_slice_fill_iter_oversized_drop() { - let arena = Arena::new(); - let out = arena.alloc_slice_fill_iter((0_u32..3000).map(|i| DropU64(u64::from(i)))); - assert_eq!(out.len(), 3000); + let arena = oversized_drop_arena(); + let out = arena.alloc_slice_fill_iter((0..OVERSIZED_DROP_LEN).map(|i| DropU64(i as u64))); + assert_eq!(out.len(), OVERSIZED_DROP_LEN); assert_eq!(out[0].0, 0); } @@ -3785,11 +3813,11 @@ mod oversized_paths_coverage { use core::mem::MaybeUninit; use multitude::Arc; - let arena = Arena::new(); + let arena = oversized_drop_arena(); // A Drop element type routes through `impl_alloc_uninit_slice_arc`; - // 3000 × 8 B = 24 KiB exceeds the fresh arena's current chunk, so - // the slice lands in a one-shot oversized chunk. - let len = 3000_usize; + // the configured element count exceeds the normal allocation threshold, + // so the slice lands in a one-shot oversized chunk. + let len = OVERSIZED_DROP_LEN; let s = arena.alloc_uninit_slice_arc::(len); // SAFETY: `s` is the unique handle, so we have exclusive write access. unsafe { @@ -4242,6 +4270,7 @@ mod alloc_drop_behavior_2 { assert_eq!(&*s, &[1, 2, 3, 4, 5]); } + #[cfg_attr(miri, ignore)] #[test] fn slice_shared_long_no_drop_succeeds() { let arena = multitude::Arena::new(); @@ -4540,6 +4569,7 @@ mod alloc_hot_path_behavior { } } + #[cfg_attr(miri, ignore)] #[test] fn arena_2266_slice_len_boundary() { let arena = Arena::new(); @@ -4892,6 +4922,7 @@ mod alloc_hot_path_behavior { assert_eq!(drops, 0, "empty Drop slices should not produce drops"); } + #[cfg_attr(miri, ignore)] #[test] fn arena_2266_large_nondrop_slice() { let arena = Arena::new(); @@ -4918,6 +4949,7 @@ mod alloc_hot_path_behavior { assert_eq!(drops, 0, "empty Drop arc slices should not produce drops"); } + #[cfg_attr(miri, ignore)] #[test] fn large_nondrop_shared_slice() { // A non-Copy, non-Drop wrapper exercises initialized shared slices. diff --git a/crates/routerama/src/dyn_builder.rs b/crates/routerama/src/dyn_builder.rs index 04f300db1..b8251f990 100644 --- a/crates/routerama/src/dyn_builder.rs +++ b/crates/routerama/src/dyn_builder.rs @@ -148,13 +148,18 @@ mod tests { use super::*; + #[cfg(miri)] + const DEEP_TRIE_SEGMENTS: usize = 512; + #[cfg(not(miri))] + const DEEP_TRIE_SEGMENTS: usize = 4_096; + #[test] fn failed_build_discards_deep_source_trie_iteratively() { std::thread::Builder::new() .stack_size(64 * 1024) .spawn(|| { let mut path = String::new(); - for index in 0..4_096 { + for index in 0..DEEP_TRIE_SEGMENTS { let _ = write!(path, "/segment{index}"); } From 9c725442e77a2ce840444e354a0be2c727f934b0 Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Thu, 27 Aug 2026 11:12:06 +0200 Subject: [PATCH 4/6] fix(miri): skip unsupported strict provenance test Keep the concurrency test in native and other Miri profiles while excluding the Unix parking_lot path that strict provenance cannot interpret. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- crates/internity/tests/basic.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/internity/tests/basic.rs b/crates/internity/tests/basic.rs index b93971e4c..17542dfd6 100644 --- a/crates/internity/tests/basic.rs +++ b/crates/internity/tests/basic.rs @@ -590,6 +590,10 @@ fn foreign_sym_resolves_to_none_without_panicking() { /// missing — so asserting the prefix property on every mid-flight snapshot /// guards the cross-shard consistency of `build_reader`. #[cfg(not(all(miri, windows)))] +#[cfg_attr( + miri_strict_provenance, + ignore = "parking_lot_core uses integer-to-pointer casts on Unix, which strict-provenance Miri rejects" +)] #[test] fn freeze_races_writer_and_stays_prefix_consistent() { use std::collections::BTreeSet; From 0a7c28379ce5a1adbc99ececdb3bc0c89fe66c91 Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 28 Aug 2026 09:07:08 +0200 Subject: [PATCH 5/6] fix(ci): exclude macro implementation crates from Miri Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- Cargo.lock | 1 + crates/multitude_macros_impl/Cargo.toml | 3 ++ crates/multitude_macros_impl/src/lib.rs | 62 +++---------------------- justfiles/anvil/checks/miri.just | 15 +++++- 4 files changed, 23 insertions(+), 58 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f0c3e56fb..c832b629a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3008,6 +3008,7 @@ dependencies = [ name = "multitude_macros_impl" version = "0.1.1" dependencies = [ + "prettyplease 0.3.0", "proc-macro2", "quote", "syn 3.0.3", diff --git a/crates/multitude_macros_impl/Cargo.toml b/crates/multitude_macros_impl/Cargo.toml index 643e126bd..b50d29861 100644 --- a/crates/multitude_macros_impl/Cargo.toml +++ b/crates/multitude_macros_impl/Cargo.toml @@ -34,6 +34,9 @@ proc-macro2 = { workspace = true } quote = { workspace = true } syn = { workspace = true, features = ["full", "derive", "printing", "parsing", "extra-traits", "proc-macro", "clone-impls"] } +[dev-dependencies] +prettyplease = { workspace = true } + # >>> anvil-managed: anvil-lints [lints] workspace = true diff --git a/crates/multitude_macros_impl/src/lib.rs b/crates/multitude_macros_impl/src/lib.rs index 7876103a9..b4899aebd 100644 --- a/crates/multitude_macros_impl/src/lib.rs +++ b/crates/multitude_macros_impl/src/lib.rs @@ -1523,64 +1523,14 @@ fn enum_tokens( #[cfg(test)] mod tests { - use std::ops::Deref; - use super::*; - struct Generated(String); - - impl Generated { - fn new(value: &str) -> Self { - let mut compact = String::with_capacity(value.len()); - let mut in_string = false; - let mut escaped = false; - for ch in value.chars() { - if in_string { - compact.push(ch); - if escaped { - escaped = false; - } else if ch == '\\' { - escaped = true; - } else if ch == '"' { - in_string = false; - } - } else if ch == '"' { - in_string = true; - compact.push(ch); - } else if !ch.is_whitespace() { - compact.push(ch); - } - } - Self(compact) - } - - fn contains(&self, expected: &str) -> bool { - self.0.contains(expected) || self.0.contains(&Self::new(expected).0) - } - - fn match_count(&self, expected: &str) -> usize { - self.0.matches(&Self::new(expected).0).count() - } - } - - impl Deref for Generated { - type Target = str; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - fn expand(source: &str) -> Generated { + fn expand(source: &str) -> String { let input: DeriveInput = syn::parse_str(source).unwrap(); let root: Path = parse_quote!(::multitude::de); let generated = super::expand(&input, &root).unwrap(); - - #[cfg(not(miri))] - syn::parse2::(generated.clone()).unwrap(); - let rendered = generated.to_string(); - - Generated::new(&rendered) + let file: syn::File = syn::parse2(generated).unwrap(); + prettyplease::unparse(&file) } #[test] @@ -1651,7 +1601,7 @@ mod tests { assert!(enumeration.contains("variant index 0 <= i < 2")); assert!(enumeration.contains("Variant2")); assert!(!enumeration.contains("Variant1,")); - assert!(compact_enumeration.contains("1u64=>::core::result::Result::Ok(__MultitudeVariantForE::Variant2)")); + assert!(compact_enumeration.contains("1u64=>{::core::result::Result::Ok(__MultitudeVariantForE::Variant2)")); assert!(!compact_enumeration.contains("2u64=>")); } @@ -1816,7 +1766,7 @@ mod tests { assert!(!variant.contains("T: ::multitude::de::DeserializeIn")); let compact: String = variant.split_whitespace().collect(); - assert_eq!(variant.match_count("let _: () = __value;"), 3); + assert_eq!(compact.matches("let_:()=__value;").count(), 3); let single_named_constructor = ["E::Single", "{", "value:__value", "}"].concat(); assert!(compact.contains(&single_named_constructor)); for constructor in [ @@ -1946,7 +1896,7 @@ mod tests { let shapes = expand("enum Shapes { New(u8), OneSkipped(#[serde(skip)] u8), Unit, Named { value: u8 } }"); let compact: String = shapes.split_whitespace().collect(); assert!(compact.contains("__MultitudeVariantForShapes::Variant0=>{let__value=__Serde::de::VariantAccess::newtype_variant_seed")); - assert!(compact.contains("__MultitudeVariantForShapes::Variant1=>__Serde::de::VariantAccess::tuple_variant(__access,0usize,")); + assert!(compact.contains("__MultitudeVariantForShapes::Variant1=>{__Serde::de::VariantAccess::tuple_variant(__access,0usize,")); assert!(shapes.contains("tuple_variant")); assert!(shapes.contains("struct_variant")); assert!(shapes.contains("unit_variant")); diff --git a/justfiles/anvil/checks/miri.just b/justfiles/anvil/checks/miri.just index 512aa2f81..dca79c397 100644 --- a/justfiles/anvil/checks/miri.just +++ b/justfiles/anvil/checks/miri.just @@ -28,6 +28,19 @@ _anvil-miri-test: if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } $packageArgs = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) + # These crates generate code rather than execute it. Their emitted unsafe + # code remains covered through consuming crates, while their own tests only + # parse and compare generated token streams. + $packageArgs += @( + '--exclude', 'data_privacy_macros_impl', + '--exclude', 'fundle_macros_impl', + '--exclude', 'internity_macros_impl', + '--exclude', 'multitude_macros_impl', + '--exclude', 'observed_macros_impl', + '--exclude', 'ohno_macros_impl', + '--exclude', 'templated_uri_macros_impl', + '--exclude', 'thread_aware_macros_impl' + ) $logRoot = Join-Path ([IO.Path]::GetTempPath()) "anvil-miri-$PID-$([guid]::NewGuid())" New-Item -ItemType Directory -Path $logRoot | Out-Null try { @@ -66,9 +79,7 @@ _anvil-miri-test: # so they do not extend the tail after short artifacts finish. switch -Regex ($name) { '^routerama_build-' { $priority = 0; break } - '^multitude_macros_impl-' { $priority = 1; break } '^rest_over_grpc-' { $priority = 2; break } - '^internity_macros_impl-' { $priority = 3; break } '^arena-' { $priority = 4; break } '^enrich_err-' { $priority = 5; break } '^routerama-' { $priority = 6; break } From 61ea2e8b20095c07ad406966935709a1577c4c2f Mon Sep 17 00:00:00 2001 From: "Stanislav Andras (from Dev Box)" Date: Fri, 28 Aug 2026 10:10:22 +0200 Subject: [PATCH 6/6] fix(ci): filter Miri packages and test artifacts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: d9192741-03aa-4e35-aaae-5c58ddc3975b --- crates/data_privacy_macros_impl/Cargo.toml | 3 + crates/fundle_macros_impl/Cargo.toml | 3 + crates/internity_macros_impl/Cargo.toml | 3 + crates/multitude_macros_impl/Cargo.toml | 3 + crates/observed_macros_impl/Cargo.toml | 3 + crates/ohno_macros_impl/Cargo.toml | 3 + crates/templated_uri_macros_impl/Cargo.toml | 3 + crates/thread_aware_macros_impl/Cargo.toml | 3 + justfiles/anvil/checks/miri.just | 66 ++++++++++++++------- 9 files changed, 68 insertions(+), 22 deletions(-) diff --git a/crates/data_privacy_macros_impl/Cargo.toml b/crates/data_privacy_macros_impl/Cargo.toml index 9d6d4faad..993edfea6 100644 --- a/crates/data_privacy_macros_impl/Cargo.toml +++ b/crates/data_privacy_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/data_privacy_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = ["proc_macro2::TokenStream", "syn::error::Error", "syn::error::Result"] diff --git a/crates/fundle_macros_impl/Cargo.toml b/crates/fundle_macros_impl/Cargo.toml index 0b4a07668..3ac0337ad 100644 --- a/crates/fundle_macros_impl/Cargo.toml +++ b/crates/fundle_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/fundle_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = ["proc_macro2::*", "syn::error::*"] diff --git a/crates/internity_macros_impl/Cargo.toml b/crates/internity_macros_impl/Cargo.toml index 01c4780bb..be30ec06f 100644 --- a/crates/internity_macros_impl/Cargo.toml +++ b/crates/internity_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/internity_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = [ "proc_macro2::*", diff --git a/crates/multitude_macros_impl/Cargo.toml b/crates/multitude_macros_impl/Cargo.toml index b50d29861..67fbf4605 100644 --- a/crates/multitude_macros_impl/Cargo.toml +++ b/crates/multitude_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/multitude_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = [ "proc_macro2::*", diff --git a/crates/observed_macros_impl/Cargo.toml b/crates/observed_macros_impl/Cargo.toml index 80c919fdd..b8ac2cd03 100644 --- a/crates/observed_macros_impl/Cargo.toml +++ b/crates/observed_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/observed_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = ["proc_macro2::*", "syn::*"] diff --git a/crates/ohno_macros_impl/Cargo.toml b/crates/ohno_macros_impl/Cargo.toml index 68f5c4590..e0c5e6696 100644 --- a/crates/ohno_macros_impl/Cargo.toml +++ b/crates/ohno_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/ohno_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = ["proc_macro2::*", "syn::*"] diff --git a/crates/templated_uri_macros_impl/Cargo.toml b/crates/templated_uri_macros_impl/Cargo.toml index 18e6f021b..ea9530392 100644 --- a/crates/templated_uri_macros_impl/Cargo.toml +++ b/crates/templated_uri_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/templated_uri_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.docs.rs] all-features = true diff --git a/crates/thread_aware_macros_impl/Cargo.toml b/crates/thread_aware_macros_impl/Cargo.toml index bb337101d..2f89c6385 100644 --- a/crates/thread_aware_macros_impl/Cargo.toml +++ b/crates/thread_aware_macros_impl/Cargo.toml @@ -17,6 +17,9 @@ homepage = { workspace = true } include = { workspace = true } repository = "https://github.com/microsoft/oxidizer/tree/main/crates/thread_aware_macros_impl" +[package.metadata.anvil.miri] +exclude = true + [package.metadata.cargo_check_external_types] allowed_external_types = [ "proc_macro2::*", diff --git a/justfiles/anvil/checks/miri.just b/justfiles/anvil/checks/miri.just index dca79c397..e8bce0c98 100644 --- a/justfiles/anvil/checks/miri.just +++ b/justfiles/anvil/checks/miri.just @@ -27,20 +27,49 @@ _anvil-miri-test: $ErrorActionPreference = 'Stop' if ($env:ANVIL_INCLUDE_AFFECTED -eq '--skip') { exit 0 } - $packageArgs = @(if ($env:ANVIL_INCLUDE_AFFECTED) { -split $env:ANVIL_INCLUDE_AFFECTED } else { '--workspace' }) - # These crates generate code rather than execute it. Their emitted unsafe - # code remains covered through consuming crates, while their own tests only - # parse and compare generated token streams. - $packageArgs += @( - '--exclude', 'data_privacy_macros_impl', - '--exclude', 'fundle_macros_impl', - '--exclude', 'internity_macros_impl', - '--exclude', 'multitude_macros_impl', - '--exclude', 'observed_macros_impl', - '--exclude', 'ohno_macros_impl', - '--exclude', 'templated_uri_macros_impl', - '--exclude', 'thread_aware_macros_impl' - ) + $metadata = & cargo metadata --no-deps --format-version 1 | ConvertFrom-Json + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + $excludedPackages = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) + $packageDirectories = @{} + foreach ($package in $metadata.packages) { + $packageDirectories[[string]$package.id] = Split-Path -Parent ([string]$package.manifest_path) + # Opted-out packages still compile as dependencies of selected consumers; + # only their own test targets are omitted from Miri. + if ($package.metadata.anvil.miri.exclude -eq $true) { + [void]$excludedPackages.Add([string]$package.name) + } + } + + if ($env:ANVIL_INCLUDE_AFFECTED) { + $tokens = @(-split $env:ANVIL_INCLUDE_AFFECTED) + $filtered = [System.Collections.Generic.List[string]]::new() + for ($i = 0; $i -lt $tokens.Count; $i++) { + if ($tokens[$i] -eq '--package') { + if (($i + 1) -ge $tokens.Count) { + Write-Error 'anvil miri: --package is missing its package spec' + exit 1 + } + $packageSpec = $tokens[++$i] + $packageName = ($packageSpec -split '@', 2)[0] + if ($excludedPackages.Contains($packageName)) { continue } + $filtered.Add('--package') + $filtered.Add($packageSpec) + } else { + $filtered.Add($tokens[$i]) + } + } + $packageArgs = $filtered.ToArray() + if (-not ($packageArgs -contains '--package')) { + Write-Host 'anvil miri: all affected packages are excluded; nothing to test' + exit 0 + } + } else { + $packageArgs = @('--workspace') + foreach ($packageName in $excludedPackages) { + $packageArgs += @('--exclude', $packageName) + } + } + $logRoot = Join-Path ([IO.Path]::GetTempPath()) "anvil-miri-$PID-$([guid]::NewGuid())" New-Item -ItemType Directory -Path $logRoot | Out-Null try { @@ -49,13 +78,6 @@ _anvil-miri-test: & cargo $toolchain miri test --all-features --tests --no-run --message-format=json-render-diagnostics @packageArgs 1> $artifactManifest $buildExitCode = $LASTEXITCODE - $metadata = & cargo metadata --no-deps --format-version 1 | ConvertFrom-Json - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } - $packageDirectories = @{} - foreach ($package in $metadata.packages) { - $packageDirectories[[string]$package.id] = Split-Path -Parent ([string]$package.manifest_path) - } - $artifacts = [System.Collections.Generic.List[object]]::new() $seenArtifacts = [System.Collections.Generic.HashSet[string]]::new([System.StringComparer]::Ordinal) foreach ($line in Get-Content -LiteralPath $artifactManifest) { @@ -66,7 +88,7 @@ _anvil-miri-test: $message = $line | ConvertFrom-Json -ErrorAction Stop if ($message.reason -eq 'compiler-message' -and $message.message.rendered) { [Console]::Error.Write($message.message.rendered) - } elseif ($message.reason -eq 'compiler-artifact' -and $message.executable) { + } elseif ($message.reason -eq 'compiler-artifact' -and $message.executable -and $message.profile.test -eq $true) { if ($seenArtifacts.Add([string]$message.executable)) { $packageId = [string]$message.package_id if (-not $packageDirectories.ContainsKey($packageId)) {