diff --git a/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230237.log b/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230237.log
new file mode 100644
index 0000000000..048c2d825c
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230237.log
@@ -0,0 +1,216 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 11 benchmark(s) in total *****
+// ***** Building 2 exe(s) in Parallel: Start *****
+// ***** Done, took 00:01:38 (98.93 sec) *****
+// ***** Failed to build in Parallel, switching to sequential build *****
+// ***** Done, took 00:00:03 (3.56 sec) *****
+// Found 1 benchmarks:
+// LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+
+// **************************
+// Benchmark: LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark.Baseline --job "IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3" --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 329662.00 ns, 329.6620 us/op
+WorkloadJitting 1: 1 op, 440548.00 ns, 440.5480 us/op
+
+OverheadJitting 2: 16 op, 279932.00 ns, 17.4958 us/op
+WorkloadJitting 2: 16 op, 1813645.00 ns, 113.3528 us/op
+
+WorkloadPilot 1: 16 op, 1104041.00 ns, 69.0026 us/op
+WorkloadPilot 2: 1456 op, 67166451.00 ns, 46.1308 us/op
+WorkloadPilot 3: 2176 op, 76232074.00 ns, 35.0331 us/op
+WorkloadPilot 4: 2864 op, 54990059.00 ns, 19.2004 us/op
+WorkloadPilot 5: 5216 op, 103296692.00 ns, 19.8038 us/op
+WorkloadPilot 6: 5056 op, 95686128.00 ns, 18.9253 us/op
+WorkloadPilot 7: 5296 op, 99203282.00 ns, 18.7317 us/op
+WorkloadPilot 8: 5344 op, 104144375.00 ns, 19.4881 us/op
+WorkloadPilot 9: 5136 op, 93310630.00 ns, 18.1680 us/op
+WorkloadPilot 10: 5504 op, 101066291.00 ns, 18.3623 us/op
+
+OverheadWarmup 1: 5504 op, 18514.00 ns, 3.3637 ns/op
+OverheadWarmup 2: 5504 op, 15771.00 ns, 2.8654 ns/op
+OverheadWarmup 3: 5504 op, 15650.00 ns, 2.8434 ns/op
+OverheadWarmup 4: 5504 op, 15522.00 ns, 2.8201 ns/op
+OverheadWarmup 5: 5504 op, 15725.00 ns, 2.8570 ns/op
+OverheadWarmup 6: 5504 op, 15595.00 ns, 2.8334 ns/op
+OverheadWarmup 7: 5504 op, 15599.00 ns, 2.8341 ns/op
+OverheadWarmup 8: 5504 op, 15769.00 ns, 2.8650 ns/op
+OverheadWarmup 9: 5504 op, 15601.00 ns, 2.8345 ns/op
+
+OverheadActual 1: 5504 op, 15957.00 ns, 2.8992 ns/op
+OverheadActual 2: 5504 op, 15832.00 ns, 2.8765 ns/op
+OverheadActual 3: 5504 op, 17221.00 ns, 3.1288 ns/op
+OverheadActual 4: 5504 op, 15701.00 ns, 2.8527 ns/op
+OverheadActual 5: 5504 op, 15703.00 ns, 2.8530 ns/op
+OverheadActual 6: 5504 op, 15700.00 ns, 2.8525 ns/op
+OverheadActual 7: 5504 op, 29718.00 ns, 5.3993 ns/op
+OverheadActual 8: 5504 op, 15626.00 ns, 2.8390 ns/op
+OverheadActual 9: 5504 op, 15610.00 ns, 2.8361 ns/op
+OverheadActual 10: 5504 op, 21303.00 ns, 3.8705 ns/op
+OverheadActual 11: 5504 op, 15816.00 ns, 2.8735 ns/op
+OverheadActual 12: 5504 op, 15816.00 ns, 2.8735 ns/op
+OverheadActual 13: 5504 op, 15548.00 ns, 2.8249 ns/op
+OverheadActual 14: 5504 op, 15593.00 ns, 2.8330 ns/op
+OverheadActual 15: 5504 op, 16904.00 ns, 3.0712 ns/op
+
+WorkloadWarmup 1: 5504 op, 111452782.00 ns, 20.2494 us/op
+WorkloadWarmup 2: 5504 op, 131013662.00 ns, 23.8034 us/op
+WorkloadWarmup 3: 5504 op, 100778633.00 ns, 18.3101 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 5504 op, 101621540.00 ns, 18.4632 us/op
+WorkloadActual 2: 5504 op, 104940024.00 ns, 19.0661 us/op
+WorkloadActual 3: 5504 op, 106892662.00 ns, 19.4209 us/op
+
+// AfterActualRun
+WorkloadResult 1: 5504 op, 101605724.00 ns, 18.4603 us/op
+WorkloadResult 2: 5504 op, 104924208.00 ns, 19.0633 us/op
+WorkloadResult 3: 5504 op, 106876846.00 ns, 19.4180 us/op
+// GC: 20 0 0 352256000 5504
+// Threading: 0 0 5504
+
+// AfterAll
+// Benchmark Process 249668 has exited with code 0.
+
+Mean = 18.981 μs, StdErr = 0.280 μs (1.47%), N = 3, StdDev = 0.484 μs
+Min = 18.460 μs, Q1 = 18.762 μs, Median = 19.063 μs, Q3 = 19.241 μs, Max = 19.418 μs
+IQR = 0.479 μs, LowerFence = 18.044 μs, UpperFence = 19.959 μs
+ConfidenceInterval = [10.147 μs; 27.814 μs] (CI 99.9%), Margin = 8.833 μs (46.54% of Mean)
+Skewness = -0.17, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 10 (90.9 %) benchmark(s) to run. Estimated finish 2025-12-12 23:04 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.html
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-default.md
+
+// * Detailed results *
+LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 18.981 μs, StdErr = 0.280 μs (1.47%), N = 3, StdDev = 0.484 μs
+Min = 18.460 μs, Q1 = 18.762 μs, Median = 19.063 μs, Q3 = 19.241 μs, Max = 19.418 μs
+IQR = 0.479 μs, LowerFence = 18.044 μs, UpperFence = 19.959 μs
+ConfidenceInterval = [10.147 μs; 27.814 μs] (CI 99.9%), Margin = 8.833 μs (46.54% of Mean)
+Skewness = -0.17, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[18.020 μs ; 18.800 μs) | @
+[18.800 μs ; 19.681 μs) | @@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ Job-RELKCN : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+IterationCount=3 IterationTime=100ms LaunchCount=1
+WarmupCount=3
+
+| Method | Mean | Error | StdDev | Ratio | RatioSD | Gen0 | Allocated | Alloc Ratio |
+|--------- |---------:|---------:|---------:|------:|--------:|-------:|----------:|------------:|
+| Baseline | 18.98 μs | 8.833 μs | 0.484 μs | 1.00 | 0.03 | 3.6337 | 62.5 KB | 1.00 |
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Ratio : Mean of the ratio distribution ([Current]/[Baseline])
+ RatioSD : Standard deviation of the ratio distribution ([Current]/[Baseline])
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ Alloc Ratio : Allocated memory ratio distribution ([Current]/[Baseline])
+ 1 μs : 1 Microsecond (0.000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:00:01 (1.95 sec), executed benchmarks: 1
+
+// Found 10 benchmarks:
+// Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Small_Mixed: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_Mixed: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase: .NET 9.0(Runtime=.NET 9.0)
+// Utf8ToAsciiConverterBaselineBenchmarks.CharArray_Medium_Mixed: .NET 9.0(Runtime=.NET 9.0)
+
+// Build Error: Standard output:
+
+ Standard error:
+ Determining projects to restore...
+/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-.NET 9.0-2/BenchmarkDotNet.Autogenerated.csproj : error NU1201: Project Umbraco.Tests.Benchmarks is not compatible with net9.0 (.NETCoreApp,Version=v9.0). Project Umbraco.Tests.Benchmarks supports: net10.0 (.NETCoreApp,Version=v10.0)
+ Failed to restore /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-.NET 9.0-2/BenchmarkDotNet.Autogenerated.csproj (in 495 ms).
+ 19 of 20 projects are up-to-date for restore.
+
+// BenchmarkDotNet has failed to build the auto-generated boilerplate code.
+// It can be found in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-.NET 9.0-2
+// Please follow the troubleshooting guide: https://benchmarkdotnet.org/articles/guides/troubleshooting.html
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-12 23:04 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.html
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-default.md
+
+// * Detailed results *
+Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: .NET 9.0(Runtime=.NET 9.0)
+Runtime = ; GC =
+There are not any results runs
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+Job=.NET 9.0 Runtime=.NET 9.0
+
+| Method | Mean | Error | Rank |
+|----------- |-----:|------:|-----:|
+| Tiny_Ascii | NA | NA | ? |
+
+Benchmarks with issues:
+ Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: .NET 9.0(Runtime=.NET 9.0)
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ Rank : Relative position of current benchmark mean among all benchmarks (Arabic style)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:00:00 (0 sec), executed benchmarks: 0
+
+Global total time: 00:01:44 (104.6 sec), executed benchmarks: 1
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230531.log b/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230531.log
new file mode 100644
index 0000000000..cb5bdf7745
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/BenchmarkRun-20251212-230531.log
@@ -0,0 +1,1494 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 11 benchmark(s) in total *****
+// ***** Building 1 exe(s) in Parallel: Start *****
+// start dotnet restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/publish/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1
+// command took 3.87 sec and exited with 0
+// start dotnet build -c Release --no-restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/publish/" --output "/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1
+// command took 93.08 sec and exited with 0
+// ***** Done, took 00:01:37 (97.22 sec) *****
+// Found 1 benchmarks:
+// LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+
+// **************************
+// Benchmark: LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark.Baseline --job "IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3" --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 227000.00 ns, 227.0000 us/op
+WorkloadJitting 1: 1 op, 421359.00 ns, 421.3590 us/op
+
+OverheadJitting 2: 16 op, 284861.00 ns, 17.8038 us/op
+WorkloadJitting 2: 16 op, 1766994.00 ns, 110.4371 us/op
+
+WorkloadPilot 1: 16 op, 1060624.00 ns, 66.2890 us/op
+WorkloadPilot 2: 1520 op, 62198704.00 ns, 40.9202 us/op
+WorkloadPilot 3: 2448 op, 83342244.00 ns, 34.0450 us/op
+WorkloadPilot 4: 2944 op, 52527147.00 ns, 17.8421 us/op
+WorkloadPilot 5: 5616 op, 105694699.00 ns, 18.8203 us/op
+WorkloadPilot 6: 5328 op, 101362680.00 ns, 19.0245 us/op
+WorkloadPilot 7: 5264 op, 98568730.00 ns, 18.7251 us/op
+WorkloadPilot 8: 5344 op, 102590987.00 ns, 19.1974 us/op
+
+OverheadWarmup 1: 5344 op, 17528.00 ns, 3.2799 ns/op
+OverheadWarmup 2: 5344 op, 15265.00 ns, 2.8565 ns/op
+OverheadWarmup 3: 5344 op, 15563.00 ns, 2.9122 ns/op
+OverheadWarmup 4: 5344 op, 15181.00 ns, 2.8408 ns/op
+OverheadWarmup 5: 5344 op, 15119.00 ns, 2.8292 ns/op
+OverheadWarmup 6: 5344 op, 15115.00 ns, 2.8284 ns/op
+OverheadWarmup 7: 5344 op, 15164.00 ns, 2.8376 ns/op
+OverheadWarmup 8: 5344 op, 15120.00 ns, 2.8293 ns/op
+
+OverheadActual 1: 5344 op, 15677.00 ns, 2.9336 ns/op
+OverheadActual 2: 5344 op, 15652.00 ns, 2.9289 ns/op
+OverheadActual 3: 5344 op, 15885.00 ns, 2.9725 ns/op
+OverheadActual 4: 5344 op, 15396.00 ns, 2.8810 ns/op
+OverheadActual 5: 5344 op, 16504.00 ns, 3.0883 ns/op
+OverheadActual 6: 5344 op, 15262.00 ns, 2.8559 ns/op
+OverheadActual 7: 5344 op, 15213.00 ns, 2.8467 ns/op
+OverheadActual 8: 5344 op, 15058.00 ns, 2.8177 ns/op
+OverheadActual 9: 5344 op, 15177.00 ns, 2.8400 ns/op
+OverheadActual 10: 5344 op, 15065.00 ns, 2.8190 ns/op
+OverheadActual 11: 5344 op, 15109.00 ns, 2.8273 ns/op
+OverheadActual 12: 5344 op, 15215.00 ns, 2.8471 ns/op
+OverheadActual 13: 5344 op, 15242.00 ns, 2.8522 ns/op
+OverheadActual 14: 5344 op, 15250.00 ns, 2.8537 ns/op
+OverheadActual 15: 5344 op, 15161.00 ns, 2.8370 ns/op
+
+WorkloadWarmup 1: 5344 op, 110995632.00 ns, 20.7701 us/op
+WorkloadWarmup 2: 5344 op, 108892180.00 ns, 20.3765 us/op
+WorkloadWarmup 3: 5344 op, 103760766.00 ns, 19.4163 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 5344 op, 101221881.00 ns, 18.9412 us/op
+WorkloadActual 2: 5344 op, 103161586.00 ns, 19.3042 us/op
+WorkloadActual 3: 5344 op, 101513960.00 ns, 18.9959 us/op
+
+// AfterActualRun
+WorkloadResult 1: 5344 op, 101206639.00 ns, 18.9384 us/op
+WorkloadResult 2: 5344 op, 103146344.00 ns, 19.3013 us/op
+WorkloadResult 3: 5344 op, 101498718.00 ns, 18.9930 us/op
+// GC: 19 0 0 342016000 5344
+// Threading: 0 0 5344
+
+// AfterAll
+// Benchmark Process 253731 has exited with code 0.
+
+Mean = 19.078 μs, StdErr = 0.113 μs (0.59%), N = 3, StdDev = 0.196 μs
+Min = 18.938 μs, Q1 = 18.966 μs, Median = 18.993 μs, Q3 = 19.147 μs, Max = 19.301 μs
+IQR = 0.181 μs, LowerFence = 18.693 μs, UpperFence = 19.419 μs
+ConfidenceInterval = [15.507 μs; 22.648 μs] (CI 99.9%), Margin = 3.570 μs (18.71% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 10 (90.9 %) benchmark(s) to run. Estimated finish 2025-12-12 23:07 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.html
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-default.md
+
+// * Detailed results *
+LoggerAllocationBenchmark.Baseline: Job-RELKCN(IterationCount=3, IterationTime=100ms, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 19.078 μs, StdErr = 0.113 μs (0.59%), N = 3, StdDev = 0.196 μs
+Min = 18.938 μs, Q1 = 18.966 μs, Median = 18.993 μs, Q3 = 19.147 μs, Max = 19.301 μs
+IQR = 0.181 μs, LowerFence = 18.693 μs, UpperFence = 19.419 μs
+ConfidenceInterval = [15.507 μs; 22.648 μs] (CI 99.9%), Margin = 3.570 μs (18.71% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[18.760 μs ; 19.479 μs) | @@@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ Job-RELKCN : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+IterationCount=3 IterationTime=100ms LaunchCount=1
+WarmupCount=3
+
+| Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio |
+|--------- |---------:|---------:|---------:|------:|-------:|----------:|------------:|
+| Baseline | 19.08 μs | 3.570 μs | 0.196 μs | 1.00 | 3.5554 | 62.5 KB | 1.00 |
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Ratio : Mean of the ratio distribution ([Current]/[Baseline])
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ Alloc Ratio : Allocated memory ratio distribution ([Current]/[Baseline])
+ 1 μs : 1 Microsecond (0.000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:00:01 (1.72 sec), executed benchmarks: 1
+
+// Found 10 benchmarks:
+// Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Small_Mixed: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_Mixed: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase: DefaultJob
+// Utf8ToAsciiConverterBaselineBenchmarks.CharArray_Medium_Mixed: DefaultJob
+
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 131 148 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii --job Default --benchmarkId 1 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 261720.00 ns, 261.7200 us/op
+WorkloadJitting 1: 1 op, 17940819.00 ns, 17.9408 ms/op
+
+OverheadJitting 2: 16 op, 724180.00 ns, 45.2613 us/op
+WorkloadJitting 2: 16 op, 673258.00 ns, 42.0786 us/op
+
+WorkloadPilot 1: 16 op, 12960.00 ns, 810.0000 ns/op
+WorkloadPilot 2: 32 op, 17014.00 ns, 531.6875 ns/op
+WorkloadPilot 3: 64 op, 27603.00 ns, 431.2969 ns/op
+WorkloadPilot 4: 128 op, 66556.00 ns, 519.9688 ns/op
+WorkloadPilot 5: 256 op, 127277.00 ns, 497.1758 ns/op
+WorkloadPilot 6: 512 op, 216696.00 ns, 423.2344 ns/op
+WorkloadPilot 7: 1024 op, 456897.00 ns, 446.1885 ns/op
+WorkloadPilot 8: 2048 op, 816466.00 ns, 398.6650 ns/op
+WorkloadPilot 9: 4096 op, 1393951.00 ns, 340.3201 ns/op
+WorkloadPilot 10: 8192 op, 2533444.00 ns, 309.2583 ns/op
+WorkloadPilot 11: 16384 op, 5047301.00 ns, 308.0628 ns/op
+WorkloadPilot 12: 32768 op, 9736870.00 ns, 297.1457 ns/op
+WorkloadPilot 13: 65536 op, 19125183.00 ns, 291.8271 ns/op
+WorkloadPilot 14: 131072 op, 37926409.00 ns, 289.3555 ns/op
+WorkloadPilot 15: 262144 op, 66105825.00 ns, 252.1737 ns/op
+WorkloadPilot 16: 524288 op, 48489923.00 ns, 92.4872 ns/op
+WorkloadPilot 17: 1048576 op, 91236327.00 ns, 87.0097 ns/op
+WorkloadPilot 18: 2097152 op, 183742853.00 ns, 87.6154 ns/op
+WorkloadPilot 19: 4194304 op, 364525229.00 ns, 86.9096 ns/op
+WorkloadPilot 20: 8388608 op, 729419983.00 ns, 86.9536 ns/op
+
+OverheadWarmup 1: 8388608 op, 40322770.00 ns, 4.8068 ns/op
+OverheadWarmup 2: 8388608 op, 40369058.00 ns, 4.8124 ns/op
+OverheadWarmup 3: 8388608 op, 40072818.00 ns, 4.7771 ns/op
+OverheadWarmup 4: 8388608 op, 40303895.00 ns, 4.8046 ns/op
+OverheadWarmup 5: 8388608 op, 40224704.00 ns, 4.7952 ns/op
+
+OverheadActual 1: 8388608 op, 40081496.00 ns, 4.7781 ns/op
+OverheadActual 2: 8388608 op, 40328617.00 ns, 4.8075 ns/op
+OverheadActual 3: 8388608 op, 40092339.00 ns, 4.7794 ns/op
+OverheadActual 4: 8388608 op, 40388940.00 ns, 4.8147 ns/op
+OverheadActual 5: 8388608 op, 40142902.00 ns, 4.7854 ns/op
+OverheadActual 6: 8388608 op, 40538948.00 ns, 4.8326 ns/op
+OverheadActual 7: 8388608 op, 39459545.00 ns, 4.7039 ns/op
+OverheadActual 8: 8388608 op, 32629318.00 ns, 3.8897 ns/op
+OverheadActual 9: 8388608 op, 32735771.00 ns, 3.9024 ns/op
+OverheadActual 10: 8388608 op, 32376398.00 ns, 3.8596 ns/op
+OverheadActual 11: 8388608 op, 32259165.00 ns, 3.8456 ns/op
+OverheadActual 12: 8388608 op, 33034925.00 ns, 3.9381 ns/op
+OverheadActual 13: 8388608 op, 32639628.00 ns, 3.8909 ns/op
+OverheadActual 14: 8388608 op, 32635944.00 ns, 3.8905 ns/op
+OverheadActual 15: 8388608 op, 32786982.00 ns, 3.9085 ns/op
+OverheadActual 16: 8388608 op, 32655129.00 ns, 3.8928 ns/op
+OverheadActual 17: 8388608 op, 32812412.00 ns, 3.9115 ns/op
+OverheadActual 18: 8388608 op, 33675849.00 ns, 4.0145 ns/op
+OverheadActual 19: 8388608 op, 32788258.00 ns, 3.9087 ns/op
+OverheadActual 20: 8388608 op, 32881285.00 ns, 3.9198 ns/op
+
+WorkloadWarmup 1: 8388608 op, 736357424.00 ns, 87.7806 ns/op
+WorkloadWarmup 2: 8388608 op, 734969277.00 ns, 87.6152 ns/op
+WorkloadWarmup 3: 8388608 op, 733159754.00 ns, 87.3995 ns/op
+WorkloadWarmup 4: 8388608 op, 731166114.00 ns, 87.1618 ns/op
+WorkloadWarmup 5: 8388608 op, 730321655.00 ns, 87.0611 ns/op
+WorkloadWarmup 6: 8388608 op, 730209413.00 ns, 87.0477 ns/op
+WorkloadWarmup 7: 8388608 op, 730327680.00 ns, 87.0618 ns/op
+WorkloadWarmup 8: 8388608 op, 726021336.00 ns, 86.5485 ns/op
+WorkloadWarmup 9: 8388608 op, 726742140.00 ns, 86.6344 ns/op
+WorkloadWarmup 10: 8388608 op, 729376541.00 ns, 86.9485 ns/op
+WorkloadWarmup 11: 8388608 op, 726662247.00 ns, 86.6249 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 8388608 op, 729520756.00 ns, 86.9657 ns/op
+WorkloadActual 2: 8388608 op, 728220545.00 ns, 86.8107 ns/op
+WorkloadActual 3: 8388608 op, 728055676.00 ns, 86.7910 ns/op
+WorkloadActual 4: 8388608 op, 729225855.00 ns, 86.9305 ns/op
+WorkloadActual 5: 8388608 op, 747507375.00 ns, 89.1098 ns/op
+WorkloadActual 6: 8388608 op, 745827106.00 ns, 88.9095 ns/op
+WorkloadActual 7: 8388608 op, 729165614.00 ns, 86.9233 ns/op
+WorkloadActual 8: 8388608 op, 724445724.00 ns, 86.3607 ns/op
+WorkloadActual 9: 8388608 op, 724081351.00 ns, 86.3172 ns/op
+WorkloadActual 10: 8388608 op, 726420424.00 ns, 86.5961 ns/op
+WorkloadActual 11: 8388608 op, 726506060.00 ns, 86.6063 ns/op
+WorkloadActual 12: 8388608 op, 723741054.00 ns, 86.2767 ns/op
+WorkloadActual 13: 8388608 op, 728243554.00 ns, 86.8134 ns/op
+WorkloadActual 14: 8388608 op, 732784823.00 ns, 87.3548 ns/op
+WorkloadActual 15: 8388608 op, 740415635.00 ns, 88.2644 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 8388608 op, 696673907.50 ns, 83.0500 ns/op
+WorkloadResult 2: 8388608 op, 695373696.50 ns, 82.8950 ns/op
+WorkloadResult 3: 8388608 op, 695208827.50 ns, 82.8754 ns/op
+WorkloadResult 4: 8388608 op, 696379006.50 ns, 83.0148 ns/op
+WorkloadResult 5: 8388608 op, 696318765.50 ns, 83.0077 ns/op
+WorkloadResult 6: 8388608 op, 691598875.50 ns, 82.4450 ns/op
+WorkloadResult 7: 8388608 op, 691234502.50 ns, 82.4016 ns/op
+WorkloadResult 8: 8388608 op, 693573575.50 ns, 82.6804 ns/op
+WorkloadResult 9: 8388608 op, 693659211.50 ns, 82.6906 ns/op
+WorkloadResult 10: 8388608 op, 690894205.50 ns, 82.3610 ns/op
+WorkloadResult 11: 8388608 op, 695396705.50 ns, 82.8977 ns/op
+WorkloadResult 12: 8388608 op, 699937974.50 ns, 83.4391 ns/op
+// GC: 23 0 0 402653184 8388608
+// Threading: 0 0 8388608
+
+// AfterAll
+// Benchmark Process 253763 has exited with code 0.
+
+Mean = 82.813 ns, StdErr = 0.091 ns (0.11%), N = 12, StdDev = 0.314 ns
+Min = 82.361 ns, Q1 = 82.622 ns, Median = 82.885 ns, Q3 = 83.009 ns, Max = 83.439 ns
+IQR = 0.388 ns, LowerFence = 82.040 ns, UpperFence = 83.591 ns
+ConfidenceInterval = [82.411 ns; 83.216 ns] (CI 99.9%), Margin = 0.402 ns (0.49% of Mean)
+Skewness = 0.16, Kurtosis = 2.13, MValue = 2
+
+// ** Remained 9 (81.8 %) benchmark(s) to run. Estimated finish 2025-12-12 23:09 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 131 148 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed --job Default --benchmarkId 2 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 292824.00 ns, 292.8240 us/op
+WorkloadJitting 1: 1 op, 18006251.00 ns, 18.0063 ms/op
+
+OverheadJitting 2: 16 op, 646315.00 ns, 40.3947 us/op
+WorkloadJitting 2: 16 op, 695017.00 ns, 43.4386 us/op
+
+WorkloadPilot 1: 16 op, 9897.00 ns, 618.5625 ns/op
+WorkloadPilot 2: 32 op, 13645.00 ns, 426.4063 ns/op
+WorkloadPilot 3: 64 op, 22550.00 ns, 352.3438 ns/op
+WorkloadPilot 4: 128 op, 51483.00 ns, 402.2109 ns/op
+WorkloadPilot 5: 256 op, 95111.00 ns, 371.5273 ns/op
+WorkloadPilot 6: 512 op, 233665.00 ns, 456.3770 ns/op
+WorkloadPilot 7: 1024 op, 448463.00 ns, 437.9521 ns/op
+WorkloadPilot 8: 2048 op, 800607.00 ns, 390.9214 ns/op
+WorkloadPilot 9: 4096 op, 1334886.00 ns, 325.8999 ns/op
+WorkloadPilot 10: 8192 op, 2536053.00 ns, 309.5768 ns/op
+WorkloadPilot 11: 16384 op, 4969723.00 ns, 303.3278 ns/op
+WorkloadPilot 12: 32768 op, 9805800.00 ns, 299.2493 ns/op
+WorkloadPilot 13: 65536 op, 19663409.00 ns, 300.0398 ns/op
+WorkloadPilot 14: 131072 op, 38433002.00 ns, 293.2205 ns/op
+WorkloadPilot 15: 262144 op, 66679821.00 ns, 254.3633 ns/op
+WorkloadPilot 16: 524288 op, 42361694.00 ns, 80.7985 ns/op
+WorkloadPilot 17: 1048576 op, 78538851.00 ns, 74.9005 ns/op
+WorkloadPilot 18: 2097152 op, 160582999.00 ns, 76.5719 ns/op
+WorkloadPilot 19: 4194304 op, 317440315.00 ns, 75.6837 ns/op
+WorkloadPilot 20: 8388608 op, 631160118.00 ns, 75.2401 ns/op
+
+OverheadWarmup 1: 8388608 op, 40236410.00 ns, 4.7966 ns/op
+OverheadWarmup 2: 8388608 op, 40411778.00 ns, 4.8175 ns/op
+OverheadWarmup 3: 8388608 op, 40432678.00 ns, 4.8200 ns/op
+OverheadWarmup 4: 8388608 op, 40284297.00 ns, 4.8023 ns/op
+OverheadWarmup 5: 8388608 op, 40550843.00 ns, 4.8340 ns/op
+OverheadWarmup 6: 8388608 op, 40294491.00 ns, 4.8035 ns/op
+
+OverheadActual 1: 8388608 op, 40322945.00 ns, 4.8069 ns/op
+OverheadActual 2: 8388608 op, 40376618.00 ns, 4.8133 ns/op
+OverheadActual 3: 8388608 op, 40408512.00 ns, 4.8171 ns/op
+OverheadActual 4: 8388608 op, 40258550.00 ns, 4.7992 ns/op
+OverheadActual 5: 8388608 op, 40524778.00 ns, 4.8309 ns/op
+OverheadActual 6: 8388608 op, 40514450.00 ns, 4.8297 ns/op
+OverheadActual 7: 8388608 op, 40450652.00 ns, 4.8221 ns/op
+OverheadActual 8: 8388608 op, 40490863.00 ns, 4.8269 ns/op
+OverheadActual 9: 8388608 op, 34618962.00 ns, 4.1269 ns/op
+OverheadActual 10: 8388608 op, 32090519.00 ns, 3.8255 ns/op
+OverheadActual 11: 8388608 op, 32132266.00 ns, 3.8305 ns/op
+OverheadActual 12: 8388608 op, 32253362.00 ns, 3.8449 ns/op
+OverheadActual 13: 8388608 op, 32318353.00 ns, 3.8526 ns/op
+OverheadActual 14: 8388608 op, 32761522.00 ns, 3.9055 ns/op
+OverheadActual 15: 8388608 op, 32816258.00 ns, 3.9120 ns/op
+OverheadActual 16: 8388608 op, 32815720.00 ns, 3.9119 ns/op
+OverheadActual 17: 8388608 op, 32795562.00 ns, 3.9095 ns/op
+OverheadActual 18: 8388608 op, 32801745.00 ns, 3.9103 ns/op
+OverheadActual 19: 8388608 op, 32756471.00 ns, 3.9049 ns/op
+OverheadActual 20: 8388608 op, 32958458.00 ns, 3.9290 ns/op
+
+WorkloadWarmup 1: 8388608 op, 639016422.00 ns, 76.1767 ns/op
+WorkloadWarmup 2: 8388608 op, 638619562.00 ns, 76.1294 ns/op
+WorkloadWarmup 3: 8388608 op, 632566294.00 ns, 75.4078 ns/op
+WorkloadWarmup 4: 8388608 op, 627329088.00 ns, 74.7835 ns/op
+WorkloadWarmup 5: 8388608 op, 624521716.00 ns, 74.4488 ns/op
+WorkloadWarmup 6: 8388608 op, 628410362.00 ns, 74.9124 ns/op
+WorkloadWarmup 7: 8388608 op, 645860267.00 ns, 76.9925 ns/op
+WorkloadWarmup 8: 8388608 op, 631158013.00 ns, 75.2399 ns/op
+WorkloadWarmup 9: 8388608 op, 630218598.00 ns, 75.1279 ns/op
+WorkloadWarmup 10: 8388608 op, 630281076.00 ns, 75.1354 ns/op
+WorkloadWarmup 11: 8388608 op, 631911039.00 ns, 75.3297 ns/op
+WorkloadWarmup 12: 8388608 op, 629953401.00 ns, 75.0963 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 8388608 op, 628806921.00 ns, 74.9596 ns/op
+WorkloadActual 2: 8388608 op, 628562862.00 ns, 74.9305 ns/op
+WorkloadActual 3: 8388608 op, 628277178.00 ns, 74.8965 ns/op
+WorkloadActual 4: 8388608 op, 627523622.00 ns, 74.8066 ns/op
+WorkloadActual 5: 8388608 op, 627434055.00 ns, 74.7960 ns/op
+WorkloadActual 6: 8388608 op, 627908457.00 ns, 74.8525 ns/op
+WorkloadActual 7: 8388608 op, 627453930.00 ns, 74.7983 ns/op
+WorkloadActual 8: 8388608 op, 631108746.00 ns, 75.2340 ns/op
+WorkloadActual 9: 8388608 op, 630907885.00 ns, 75.2101 ns/op
+WorkloadActual 10: 8388608 op, 630972378.00 ns, 75.2178 ns/op
+WorkloadActual 11: 8388608 op, 643657752.00 ns, 76.7300 ns/op
+WorkloadActual 12: 8388608 op, 647630524.00 ns, 77.2036 ns/op
+WorkloadActual 13: 8388608 op, 645583624.00 ns, 76.9596 ns/op
+WorkloadActual 14: 8388608 op, 629985679.00 ns, 75.1001 ns/op
+WorkloadActual 15: 8388608 op, 627528030.00 ns, 74.8072 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 8388608 op, 595919563.00 ns, 71.0391 ns/op
+WorkloadResult 2: 8388608 op, 595675504.00 ns, 71.0101 ns/op
+WorkloadResult 3: 8388608 op, 595389820.00 ns, 70.9760 ns/op
+WorkloadResult 4: 8388608 op, 594636264.00 ns, 70.8862 ns/op
+WorkloadResult 5: 8388608 op, 594546697.00 ns, 70.8755 ns/op
+WorkloadResult 6: 8388608 op, 595021099.00 ns, 70.9320 ns/op
+WorkloadResult 7: 8388608 op, 594566572.00 ns, 70.8779 ns/op
+WorkloadResult 8: 8388608 op, 598221388.00 ns, 71.3135 ns/op
+WorkloadResult 9: 8388608 op, 598020527.00 ns, 71.2896 ns/op
+WorkloadResult 10: 8388608 op, 598085020.00 ns, 71.2973 ns/op
+WorkloadResult 11: 8388608 op, 597098321.00 ns, 71.1797 ns/op
+WorkloadResult 12: 8388608 op, 594640672.00 ns, 70.8867 ns/op
+// GC: 23 0 0 402653184 8388608
+// Threading: 0 0 8388608
+
+// AfterAll
+// Benchmark Process 253856 has exited with code 0.
+
+Mean = 71.047 ns, StdErr = 0.051 ns (0.07%), N = 12, StdDev = 0.176 ns
+Min = 70.875 ns, Q1 = 70.887 ns, Median = 70.993 ns, Q3 = 71.207 ns, Max = 71.314 ns
+IQR = 0.321 ns, LowerFence = 70.406 ns, UpperFence = 71.688 ns
+ConfidenceInterval = [70.822 ns; 71.272 ns] (CI 99.9%), Margin = 0.225 ns (0.32% of Mean)
+Skewness = 0.48, Kurtosis = 1.4, MValue = 2
+
+// ** Remained 8 (72.7 %) benchmark(s) to run. Estimated finish 2025-12-12 23:09 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 131 148 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii --job Default --benchmarkId 3 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 255597.00 ns, 255.5970 us/op
+WorkloadJitting 1: 1 op, 17644685.00 ns, 17.6447 ms/op
+
+OverheadJitting 2: 16 op, 675325.00 ns, 42.2078 us/op
+WorkloadJitting 2: 16 op, 755417.00 ns, 47.2136 us/op
+
+WorkloadPilot 1: 16 op, 49086.00 ns, 3.0679 us/op
+WorkloadPilot 2: 32 op, 99443.00 ns, 3.1076 us/op
+WorkloadPilot 3: 64 op, 246391.00 ns, 3.8499 us/op
+WorkloadPilot 4: 128 op, 433015.00 ns, 3.3829 us/op
+WorkloadPilot 5: 256 op, 702525.00 ns, 2.7442 us/op
+WorkloadPilot 6: 512 op, 1247068.00 ns, 2.4357 us/op
+WorkloadPilot 7: 1024 op, 2394934.00 ns, 2.3388 us/op
+WorkloadPilot 8: 2048 op, 4458425.00 ns, 2.1770 us/op
+WorkloadPilot 9: 4096 op, 8890083.00 ns, 2.1704 us/op
+WorkloadPilot 10: 8192 op, 18039694.00 ns, 2.2021 us/op
+WorkloadPilot 11: 16384 op, 35469899.00 ns, 2.1649 us/op
+WorkloadPilot 12: 32768 op, 76937350.00 ns, 2.3479 us/op
+WorkloadPilot 13: 65536 op, 51422664.00 ns, 784.6476 ns/op
+WorkloadPilot 14: 131072 op, 93714921.00 ns, 714.9881 ns/op
+WorkloadPilot 15: 262144 op, 185182293.00 ns, 706.4144 ns/op
+WorkloadPilot 16: 524288 op, 366550298.00 ns, 699.1392 ns/op
+WorkloadPilot 17: 1048576 op, 730478728.00 ns, 696.6388 ns/op
+
+OverheadWarmup 1: 1048576 op, 4667223.00 ns, 4.4510 ns/op
+OverheadWarmup 2: 1048576 op, 4666508.00 ns, 4.4503 ns/op
+OverheadWarmup 3: 1048576 op, 4636412.00 ns, 4.4216 ns/op
+OverheadWarmup 4: 1048576 op, 4742795.00 ns, 4.5231 ns/op
+OverheadWarmup 5: 1048576 op, 4644598.00 ns, 4.4294 ns/op
+OverheadWarmup 6: 1048576 op, 4657241.00 ns, 4.4415 ns/op
+OverheadWarmup 7: 1048576 op, 4647420.00 ns, 4.4321 ns/op
+
+OverheadActual 1: 1048576 op, 4653613.00 ns, 4.4380 ns/op
+OverheadActual 2: 1048576 op, 4649877.00 ns, 4.4345 ns/op
+OverheadActual 3: 1048576 op, 4650434.00 ns, 4.4350 ns/op
+OverheadActual 4: 1048576 op, 4627900.00 ns, 4.4135 ns/op
+OverheadActual 5: 1048576 op, 4652330.00 ns, 4.4368 ns/op
+OverheadActual 6: 1048576 op, 4707015.00 ns, 4.4890 ns/op
+OverheadActual 7: 1048576 op, 4621228.00 ns, 4.4071 ns/op
+OverheadActual 8: 1048576 op, 4645252.00 ns, 4.4301 ns/op
+OverheadActual 9: 1048576 op, 4660636.00 ns, 4.4447 ns/op
+OverheadActual 10: 1048576 op, 4632503.00 ns, 4.4179 ns/op
+OverheadActual 11: 1048576 op, 4622152.00 ns, 4.4080 ns/op
+OverheadActual 12: 1048576 op, 4677384.00 ns, 4.4607 ns/op
+OverheadActual 13: 1048576 op, 4644916.00 ns, 4.4297 ns/op
+OverheadActual 14: 1048576 op, 4653523.00 ns, 4.4379 ns/op
+OverheadActual 15: 1048576 op, 4643956.00 ns, 4.4288 ns/op
+
+WorkloadWarmup 1: 1048576 op, 737643971.00 ns, 703.4721 ns/op
+WorkloadWarmup 2: 1048576 op, 736397307.00 ns, 702.2832 ns/op
+WorkloadWarmup 3: 1048576 op, 734794863.00 ns, 700.7550 ns/op
+WorkloadWarmup 4: 1048576 op, 731912228.00 ns, 698.0059 ns/op
+WorkloadWarmup 5: 1048576 op, 730967348.00 ns, 697.1048 ns/op
+WorkloadWarmup 6: 1048576 op, 737649002.00 ns, 703.4769 ns/op
+WorkloadWarmup 7: 1048576 op, 746107048.00 ns, 711.5431 ns/op
+WorkloadWarmup 8: 1048576 op, 744084510.00 ns, 709.6143 ns/op
+WorkloadWarmup 9: 1048576 op, 733620789.00 ns, 699.6353 ns/op
+WorkloadWarmup 10: 1048576 op, 732060198.00 ns, 698.1470 ns/op
+WorkloadWarmup 11: 1048576 op, 732129736.00 ns, 698.2133 ns/op
+WorkloadWarmup 12: 1048576 op, 729908183.00 ns, 696.0947 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 743488178.00 ns, 709.0456 ns/op
+WorkloadActual 2: 1048576 op, 732774395.00 ns, 698.8281 ns/op
+WorkloadActual 3: 1048576 op, 732529700.00 ns, 698.5948 ns/op
+WorkloadActual 4: 1048576 op, 731863269.00 ns, 697.9592 ns/op
+WorkloadActual 5: 1048576 op, 734364993.00 ns, 700.3450 ns/op
+WorkloadActual 6: 1048576 op, 730360232.00 ns, 696.5258 ns/op
+WorkloadActual 7: 1048576 op, 733851640.00 ns, 699.8555 ns/op
+WorkloadActual 8: 1048576 op, 732560008.00 ns, 698.6237 ns/op
+WorkloadActual 9: 1048576 op, 732304620.00 ns, 698.3801 ns/op
+WorkloadActual 10: 1048576 op, 734541450.00 ns, 700.5133 ns/op
+WorkloadActual 11: 1048576 op, 746711682.00 ns, 712.1198 ns/op
+WorkloadActual 12: 1048576 op, 731391497.00 ns, 697.5093 ns/op
+WorkloadActual 13: 1048576 op, 733140094.00 ns, 699.1769 ns/op
+WorkloadActual 14: 1048576 op, 741323702.00 ns, 706.9814 ns/op
+WorkloadActual 15: 1048576 op, 748565293.00 ns, 713.8875 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 738838301.00 ns, 704.6111 ns/op
+WorkloadResult 2: 1048576 op, 728124518.00 ns, 694.3937 ns/op
+WorkloadResult 3: 1048576 op, 727879823.00 ns, 694.1603 ns/op
+WorkloadResult 4: 1048576 op, 727213392.00 ns, 693.5247 ns/op
+WorkloadResult 5: 1048576 op, 729715116.00 ns, 695.9106 ns/op
+WorkloadResult 6: 1048576 op, 725710355.00 ns, 692.0913 ns/op
+WorkloadResult 7: 1048576 op, 729201763.00 ns, 695.4210 ns/op
+WorkloadResult 8: 1048576 op, 727910131.00 ns, 694.1892 ns/op
+WorkloadResult 9: 1048576 op, 727654743.00 ns, 693.9456 ns/op
+WorkloadResult 10: 1048576 op, 729891573.00 ns, 696.0788 ns/op
+WorkloadResult 11: 1048576 op, 726741620.00 ns, 693.0748 ns/op
+WorkloadResult 12: 1048576 op, 728490217.00 ns, 694.7424 ns/op
+WorkloadResult 13: 1048576 op, 736673825.00 ns, 702.5469 ns/op
+// GC: 13 0 0 234881024 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 253946 has exited with code 0.
+
+Mean = 695.745 ns, StdErr = 1.018 ns (0.15%), N = 13, StdDev = 3.669 ns
+Min = 692.091 ns, Q1 = 693.946 ns, Median = 694.394 ns, Q3 = 695.911 ns, Max = 704.611 ns
+IQR = 1.965 ns, LowerFence = 690.998 ns, UpperFence = 698.858 ns
+ConfidenceInterval = [691.352 ns; 700.139 ns] (CI 99.9%), Margin = 4.394 ns (0.63% of Mean)
+Skewness = 1.43, Kurtosis = 3.65, MValue = 2
+
+// ** Remained 7 (63.6 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Small_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Small_Mixed --job Default --benchmarkId 4 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 276204.00 ns, 276.2040 us/op
+WorkloadJitting 1: 1 op, 17820181.00 ns, 17.8202 ms/op
+
+OverheadJitting 2: 16 op, 692581.00 ns, 43.2863 us/op
+WorkloadJitting 2: 16 op, 769154.00 ns, 48.0721 us/op
+
+WorkloadPilot 1: 16 op, 53870.00 ns, 3.3669 us/op
+WorkloadPilot 2: 32 op, 109819.00 ns, 3.4318 us/op
+WorkloadPilot 3: 64 op, 254720.00 ns, 3.9800 us/op
+WorkloadPilot 4: 128 op, 481430.00 ns, 3.7612 us/op
+WorkloadPilot 5: 256 op, 811078.00 ns, 3.1683 us/op
+WorkloadPilot 6: 512 op, 1481081.00 ns, 2.8927 us/op
+WorkloadPilot 7: 1024 op, 2811840.00 ns, 2.7459 us/op
+WorkloadPilot 8: 2048 op, 5376144.00 ns, 2.6251 us/op
+WorkloadPilot 9: 4096 op, 10726363.00 ns, 2.6187 us/op
+WorkloadPilot 10: 8192 op, 21311826.00 ns, 2.6015 us/op
+WorkloadPilot 11: 16384 op, 42429432.00 ns, 2.5897 us/op
+WorkloadPilot 12: 32768 op, 65293418.00 ns, 1.9926 us/op
+WorkloadPilot 13: 65536 op, 50256050.00 ns, 766.8465 ns/op
+WorkloadPilot 14: 131072 op, 93780684.00 ns, 715.4898 ns/op
+WorkloadPilot 15: 262144 op, 180288138.00 ns, 687.7447 ns/op
+WorkloadPilot 16: 524288 op, 361012527.00 ns, 688.5767 ns/op
+WorkloadPilot 17: 1048576 op, 717805354.00 ns, 684.5525 ns/op
+
+OverheadWarmup 1: 1048576 op, 5033060.00 ns, 4.7999 ns/op
+OverheadWarmup 2: 1048576 op, 5021817.00 ns, 4.7892 ns/op
+OverheadWarmup 3: 1048576 op, 5057378.00 ns, 4.8231 ns/op
+OverheadWarmup 4: 1048576 op, 5086918.00 ns, 4.8513 ns/op
+OverheadWarmup 5: 1048576 op, 5010647.00 ns, 4.7785 ns/op
+OverheadWarmup 6: 1048576 op, 5003785.00 ns, 4.7720 ns/op
+OverheadWarmup 7: 1048576 op, 5042769.00 ns, 4.8092 ns/op
+OverheadWarmup 8: 1048576 op, 5012259.00 ns, 4.7801 ns/op
+
+OverheadActual 1: 1048576 op, 5052099.00 ns, 4.8181 ns/op
+OverheadActual 2: 1048576 op, 5027237.00 ns, 4.7943 ns/op
+OverheadActual 3: 1048576 op, 5019958.00 ns, 4.7874 ns/op
+OverheadActual 4: 1048576 op, 5022806.00 ns, 4.7901 ns/op
+OverheadActual 5: 1048576 op, 5047609.00 ns, 4.8138 ns/op
+OverheadActual 6: 1048576 op, 5012665.00 ns, 4.7804 ns/op
+OverheadActual 7: 1048576 op, 5020553.00 ns, 4.7880 ns/op
+OverheadActual 8: 1048576 op, 5038443.00 ns, 4.8050 ns/op
+OverheadActual 9: 1048576 op, 5074935.00 ns, 4.8398 ns/op
+OverheadActual 10: 1048576 op, 5037269.00 ns, 4.8039 ns/op
+OverheadActual 11: 1048576 op, 4995923.00 ns, 4.7645 ns/op
+OverheadActual 12: 1048576 op, 5031293.00 ns, 4.7982 ns/op
+OverheadActual 13: 1048576 op, 5006964.00 ns, 4.7750 ns/op
+OverheadActual 14: 1048576 op, 5025032.00 ns, 4.7922 ns/op
+OverheadActual 15: 1048576 op, 5019886.00 ns, 4.7873 ns/op
+
+WorkloadWarmup 1: 1048576 op, 723779114.00 ns, 690.2496 ns/op
+WorkloadWarmup 2: 1048576 op, 719112545.00 ns, 685.7992 ns/op
+WorkloadWarmup 3: 1048576 op, 722344792.00 ns, 688.8817 ns/op
+WorkloadWarmup 4: 1048576 op, 718140899.00 ns, 684.8725 ns/op
+WorkloadWarmup 5: 1048576 op, 717581510.00 ns, 684.3391 ns/op
+WorkloadWarmup 6: 1048576 op, 717338750.00 ns, 684.1075 ns/op
+WorkloadWarmup 7: 1048576 op, 719823573.00 ns, 686.4773 ns/op
+WorkloadWarmup 8: 1048576 op, 717512554.00 ns, 684.2733 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 718592757.00 ns, 685.3035 ns/op
+WorkloadActual 2: 1048576 op, 715823248.00 ns, 682.6622 ns/op
+WorkloadActual 3: 1048576 op, 715815876.00 ns, 682.6552 ns/op
+WorkloadActual 4: 1048576 op, 715925432.00 ns, 682.7597 ns/op
+WorkloadActual 5: 1048576 op, 718558940.00 ns, 685.2712 ns/op
+WorkloadActual 6: 1048576 op, 717063372.00 ns, 683.8449 ns/op
+WorkloadActual 7: 1048576 op, 718576987.00 ns, 685.2884 ns/op
+WorkloadActual 8: 1048576 op, 718239250.00 ns, 684.9663 ns/op
+WorkloadActual 9: 1048576 op, 734136342.00 ns, 700.1270 ns/op
+WorkloadActual 10: 1048576 op, 737418373.00 ns, 703.2570 ns/op
+WorkloadActual 11: 1048576 op, 732958299.00 ns, 699.0035 ns/op
+WorkloadActual 12: 1048576 op, 734538192.00 ns, 700.5102 ns/op
+WorkloadActual 13: 1048576 op, 734682729.00 ns, 700.6480 ns/op
+WorkloadActual 14: 1048576 op, 734246170.00 ns, 700.2317 ns/op
+WorkloadActual 15: 1048576 op, 727171955.00 ns, 693.4852 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 713567725.00 ns, 680.5112 ns/op
+WorkloadResult 2: 1048576 op, 710798216.00 ns, 677.8700 ns/op
+WorkloadResult 3: 1048576 op, 710790844.00 ns, 677.8630 ns/op
+WorkloadResult 4: 1048576 op, 710900400.00 ns, 677.9675 ns/op
+WorkloadResult 5: 1048576 op, 713533908.00 ns, 680.4790 ns/op
+WorkloadResult 6: 1048576 op, 712038340.00 ns, 679.0527 ns/op
+WorkloadResult 7: 1048576 op, 713551955.00 ns, 680.4962 ns/op
+WorkloadResult 8: 1048576 op, 713214218.00 ns, 680.1741 ns/op
+WorkloadResult 9: 1048576 op, 729111310.00 ns, 695.3347 ns/op
+WorkloadResult 10: 1048576 op, 732393341.00 ns, 698.4647 ns/op
+WorkloadResult 11: 1048576 op, 727933267.00 ns, 694.2113 ns/op
+WorkloadResult 12: 1048576 op, 729513160.00 ns, 695.7180 ns/op
+WorkloadResult 13: 1048576 op, 729657697.00 ns, 695.8558 ns/op
+WorkloadResult 14: 1048576 op, 729221138.00 ns, 695.4395 ns/op
+WorkloadResult 15: 1048576 op, 722146923.00 ns, 688.6930 ns/op
+// GC: 13 0 0 234881024 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 254040 has exited with code 0.
+
+Mean = 686.542 ns, StdErr = 2.142 ns (0.31%), N = 15, StdDev = 8.295 ns
+Min = 677.863 ns, Q1 = 679.613 ns, Median = 680.511 ns, Q3 = 695.387 ns, Max = 698.465 ns
+IQR = 15.774 ns, LowerFence = 655.953 ns, UpperFence = 719.048 ns
+ConfidenceInterval = [677.674 ns; 695.410 ns] (CI 99.9%), Margin = 8.868 ns (1.29% of Mean)
+Skewness = 0.22, Kurtosis = 1.07, MValue = 2
+
+// ** Remained 6 (54.5 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii --job Default --benchmarkId 5 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 312997.00 ns, 312.9970 us/op
+WorkloadJitting 1: 1 op, 17993238.00 ns, 17.9932 ms/op
+
+OverheadJitting 2: 16 op, 668427.00 ns, 41.7767 us/op
+WorkloadJitting 2: 16 op, 1738116.00 ns, 108.6323 us/op
+
+WorkloadPilot 1: 16 op, 606560.00 ns, 37.9100 us/op
+WorkloadPilot 2: 32 op, 1092078.00 ns, 34.1274 us/op
+WorkloadPilot 3: 64 op, 1870623.00 ns, 29.2285 us/op
+WorkloadPilot 4: 128 op, 3601645.00 ns, 28.1379 us/op
+WorkloadPilot 5: 256 op, 7068744.00 ns, 27.6123 us/op
+WorkloadPilot 6: 512 op, 14151294.00 ns, 27.6392 us/op
+WorkloadPilot 7: 1024 op, 28163524.00 ns, 27.5034 us/op
+WorkloadPilot 8: 2048 op, 57772447.00 ns, 28.2092 us/op
+WorkloadPilot 9: 4096 op, 47802121.00 ns, 11.6704 us/op
+WorkloadPilot 10: 8192 op, 49736311.00 ns, 6.0713 us/op
+WorkloadPilot 11: 16384 op, 99574942.00 ns, 6.0776 us/op
+WorkloadPilot 12: 32768 op, 197497443.00 ns, 6.0271 us/op
+WorkloadPilot 13: 65536 op, 394497110.00 ns, 6.0195 us/op
+WorkloadPilot 14: 131072 op, 792204847.00 ns, 6.0440 us/op
+
+OverheadWarmup 1: 131072 op, 662330.00 ns, 5.0532 ns/op
+OverheadWarmup 2: 131072 op, 637262.00 ns, 4.8619 ns/op
+OverheadWarmup 3: 131072 op, 641236.00 ns, 4.8922 ns/op
+OverheadWarmup 4: 131072 op, 652439.00 ns, 4.9777 ns/op
+OverheadWarmup 5: 131072 op, 623060.00 ns, 4.7536 ns/op
+OverheadWarmup 6: 131072 op, 637972.00 ns, 4.8673 ns/op
+OverheadWarmup 7: 131072 op, 644087.00 ns, 4.9140 ns/op
+OverheadWarmup 8: 131072 op, 636713.00 ns, 4.8577 ns/op
+
+OverheadActual 1: 131072 op, 633680.00 ns, 4.8346 ns/op
+OverheadActual 2: 131072 op, 638254.00 ns, 4.8695 ns/op
+OverheadActual 3: 131072 op, 656022.00 ns, 5.0051 ns/op
+OverheadActual 4: 131072 op, 623390.00 ns, 4.7561 ns/op
+OverheadActual 5: 131072 op, 652414.00 ns, 4.9775 ns/op
+OverheadActual 6: 131072 op, 622159.00 ns, 4.7467 ns/op
+OverheadActual 7: 131072 op, 638842.00 ns, 4.8740 ns/op
+OverheadActual 8: 131072 op, 638062.00 ns, 4.8680 ns/op
+OverheadActual 9: 131072 op, 656783.00 ns, 5.0109 ns/op
+OverheadActual 10: 131072 op, 682631.00 ns, 5.2081 ns/op
+OverheadActual 11: 131072 op, 644564.00 ns, 4.9176 ns/op
+OverheadActual 12: 131072 op, 622540.00 ns, 4.7496 ns/op
+OverheadActual 13: 131072 op, 635670.00 ns, 4.8498 ns/op
+OverheadActual 14: 131072 op, 630494.00 ns, 4.8103 ns/op
+OverheadActual 15: 131072 op, 658291.00 ns, 5.0224 ns/op
+
+WorkloadWarmup 1: 131072 op, 791498119.00 ns, 6.0387 us/op
+WorkloadWarmup 2: 131072 op, 792807980.00 ns, 6.0486 us/op
+WorkloadWarmup 3: 131072 op, 798010444.00 ns, 6.0883 us/op
+WorkloadWarmup 4: 131072 op, 794131695.00 ns, 6.0587 us/op
+WorkloadWarmup 5: 131072 op, 795886646.00 ns, 6.0721 us/op
+WorkloadWarmup 6: 131072 op, 793211460.00 ns, 6.0517 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 131072 op, 792872358.00 ns, 6.0491 us/op
+WorkloadActual 2: 131072 op, 778157030.00 ns, 5.9369 us/op
+WorkloadActual 3: 131072 op, 787375908.00 ns, 6.0072 us/op
+WorkloadActual 4: 131072 op, 785822886.00 ns, 5.9954 us/op
+WorkloadActual 5: 131072 op, 784919762.00 ns, 5.9885 us/op
+WorkloadActual 6: 131072 op, 789152482.00 ns, 6.0208 us/op
+WorkloadActual 7: 131072 op, 787498464.00 ns, 6.0081 us/op
+WorkloadActual 8: 131072 op, 781885662.00 ns, 5.9653 us/op
+WorkloadActual 9: 131072 op, 784525173.00 ns, 5.9855 us/op
+WorkloadActual 10: 131072 op, 785750115.00 ns, 5.9948 us/op
+WorkloadActual 11: 131072 op, 781243248.00 ns, 5.9604 us/op
+WorkloadActual 12: 131072 op, 785139873.00 ns, 5.9901 us/op
+WorkloadActual 13: 131072 op, 791974216.00 ns, 6.0423 us/op
+WorkloadActual 14: 131072 op, 788875938.00 ns, 6.0186 us/op
+WorkloadActual 15: 131072 op, 790408919.00 ns, 6.0303 us/op
+
+// AfterActualRun
+WorkloadResult 1: 131072 op, 792234104.00 ns, 6.0443 us/op
+WorkloadResult 2: 131072 op, 777518776.00 ns, 5.9320 us/op
+WorkloadResult 3: 131072 op, 786737654.00 ns, 6.0023 us/op
+WorkloadResult 4: 131072 op, 785184632.00 ns, 5.9905 us/op
+WorkloadResult 5: 131072 op, 784281508.00 ns, 5.9836 us/op
+WorkloadResult 6: 131072 op, 788514228.00 ns, 6.0159 us/op
+WorkloadResult 7: 131072 op, 786860210.00 ns, 6.0033 us/op
+WorkloadResult 8: 131072 op, 781247408.00 ns, 5.9604 us/op
+WorkloadResult 9: 131072 op, 783886919.00 ns, 5.9806 us/op
+WorkloadResult 10: 131072 op, 785111861.00 ns, 5.9899 us/op
+WorkloadResult 11: 131072 op, 780604994.00 ns, 5.9555 us/op
+WorkloadResult 12: 131072 op, 784501619.00 ns, 5.9853 us/op
+WorkloadResult 13: 131072 op, 791335962.00 ns, 6.0374 us/op
+WorkloadResult 14: 131072 op, 788237684.00 ns, 6.0138 us/op
+WorkloadResult 15: 131072 op, 789770665.00 ns, 6.0255 us/op
+// GC: 62 0 0 1080033280 131072
+// Threading: 0 0 131072
+
+// AfterAll
+// Benchmark Process 254112 has exited with code 0.
+
+Mean = 5.995 μs, StdErr = 0.008 μs (0.13%), N = 15, StdDev = 0.031 μs
+Min = 5.932 μs, Q1 = 5.982 μs, Median = 5.990 μs, Q3 = 6.015 μs, Max = 6.044 μs
+IQR = 0.033 μs, LowerFence = 5.933 μs, UpperFence = 6.064 μs
+ConfidenceInterval = [5.962 μs; 6.028 μs] (CI 99.9%), Margin = 0.033 μs (0.55% of Mean)
+Skewness = -0.24, Kurtosis = 2.22, MValue = 2
+
+// ** Remained 5 (45.5 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed --job Default --benchmarkId 6 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 258236.00 ns, 258.2360 us/op
+WorkloadJitting 1: 1 op, 18142808.00 ns, 18.1428 ms/op
+
+OverheadJitting 2: 16 op, 703641.00 ns, 43.9776 us/op
+WorkloadJitting 2: 16 op, 1899906.00 ns, 118.7441 us/op
+
+WorkloadPilot 1: 16 op, 672593.00 ns, 42.0371 us/op
+WorkloadPilot 2: 32 op, 1272528.00 ns, 39.7665 us/op
+WorkloadPilot 3: 64 op, 2194837.00 ns, 34.2943 us/op
+WorkloadPilot 4: 128 op, 4264675.00 ns, 33.3178 us/op
+WorkloadPilot 5: 256 op, 8401086.00 ns, 32.8167 us/op
+WorkloadPilot 6: 512 op, 16516488.00 ns, 32.2588 us/op
+WorkloadPilot 7: 1024 op, 32805701.00 ns, 32.0368 us/op
+WorkloadPilot 8: 2048 op, 70101103.00 ns, 34.2291 us/op
+WorkloadPilot 9: 4096 op, 34279337.00 ns, 8.3690 us/op
+WorkloadPilot 10: 8192 op, 58676048.00 ns, 7.1626 us/op
+WorkloadPilot 11: 16384 op, 116398269.00 ns, 7.1044 us/op
+WorkloadPilot 12: 32768 op, 232030285.00 ns, 7.0810 us/op
+WorkloadPilot 13: 65536 op, 464138544.00 ns, 7.0822 us/op
+WorkloadPilot 14: 131072 op, 935166055.00 ns, 7.1348 us/op
+
+OverheadWarmup 1: 131072 op, 639014.00 ns, 4.8753 ns/op
+OverheadWarmup 2: 131072 op, 622111.00 ns, 4.7463 ns/op
+OverheadWarmup 3: 131072 op, 651085.00 ns, 4.9674 ns/op
+OverheadWarmup 4: 131072 op, 666109.00 ns, 5.0820 ns/op
+OverheadWarmup 5: 131072 op, 620065.00 ns, 4.7307 ns/op
+OverheadWarmup 6: 131072 op, 624032.00 ns, 4.7610 ns/op
+OverheadWarmup 7: 131072 op, 638699.00 ns, 4.8729 ns/op
+OverheadWarmup 8: 131072 op, 644936.00 ns, 4.9205 ns/op
+OverheadWarmup 9: 131072 op, 621353.00 ns, 4.7405 ns/op
+
+OverheadActual 1: 131072 op, 621713.00 ns, 4.7433 ns/op
+OverheadActual 2: 131072 op, 676176.00 ns, 5.1588 ns/op
+OverheadActual 3: 131072 op, 640738.00 ns, 4.8884 ns/op
+OverheadActual 4: 131072 op, 639553.00 ns, 4.8794 ns/op
+OverheadActual 5: 131072 op, 638653.00 ns, 4.8725 ns/op
+OverheadActual 6: 131072 op, 618778.00 ns, 4.7209 ns/op
+OverheadActual 7: 131072 op, 674699.00 ns, 5.1475 ns/op
+OverheadActual 8: 131072 op, 652228.00 ns, 4.9761 ns/op
+OverheadActual 9: 131072 op, 621270.00 ns, 4.7399 ns/op
+OverheadActual 10: 131072 op, 625975.00 ns, 4.7758 ns/op
+OverheadActual 11: 131072 op, 640145.00 ns, 4.8839 ns/op
+OverheadActual 12: 131072 op, 668542.00 ns, 5.1006 ns/op
+OverheadActual 13: 131072 op, 631485.00 ns, 4.8178 ns/op
+OverheadActual 14: 131072 op, 660160.00 ns, 5.0366 ns/op
+OverheadActual 15: 131072 op, 643738.00 ns, 4.9113 ns/op
+
+WorkloadWarmup 1: 131072 op, 943302356.00 ns, 7.1968 us/op
+WorkloadWarmup 2: 131072 op, 939354545.00 ns, 7.1667 us/op
+WorkloadWarmup 3: 131072 op, 933237523.00 ns, 7.1200 us/op
+WorkloadWarmup 4: 131072 op, 943807500.00 ns, 7.2007 us/op
+WorkloadWarmup 5: 131072 op, 956728543.00 ns, 7.2993 us/op
+WorkloadWarmup 6: 131072 op, 930002788.00 ns, 7.0954 us/op
+WorkloadWarmup 7: 131072 op, 925867597.00 ns, 7.0638 us/op
+WorkloadWarmup 8: 131072 op, 926524501.00 ns, 7.0688 us/op
+WorkloadWarmup 9: 131072 op, 931169921.00 ns, 7.1043 us/op
+WorkloadWarmup 10: 131072 op, 941095638.00 ns, 7.1800 us/op
+WorkloadWarmup 11: 131072 op, 941226170.00 ns, 7.1810 us/op
+WorkloadWarmup 12: 131072 op, 934534254.00 ns, 7.1299 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 131072 op, 935936020.00 ns, 7.1406 us/op
+WorkloadActual 2: 131072 op, 952519787.00 ns, 7.2671 us/op
+WorkloadActual 3: 131072 op, 939061158.00 ns, 7.1645 us/op
+WorkloadActual 4: 131072 op, 949259511.00 ns, 7.2423 us/op
+WorkloadActual 5: 131072 op, 931258356.00 ns, 7.1049 us/op
+WorkloadActual 6: 131072 op, 934378087.00 ns, 7.1287 us/op
+WorkloadActual 7: 131072 op, 930232864.00 ns, 7.0971 us/op
+WorkloadActual 8: 131072 op, 928227215.00 ns, 7.0818 us/op
+WorkloadActual 9: 131072 op, 932337992.00 ns, 7.1132 us/op
+WorkloadActual 10: 131072 op, 935920314.00 ns, 7.1405 us/op
+WorkloadActual 11: 131072 op, 935159329.00 ns, 7.1347 us/op
+WorkloadActual 12: 131072 op, 931838329.00 ns, 7.1094 us/op
+WorkloadActual 13: 131072 op, 935282155.00 ns, 7.1356 us/op
+WorkloadActual 14: 131072 op, 934696429.00 ns, 7.1312 us/op
+WorkloadActual 15: 131072 op, 930302314.00 ns, 7.0976 us/op
+
+// AfterActualRun
+WorkloadResult 1: 131072 op, 935295875.00 ns, 7.1357 us/op
+WorkloadResult 2: 131072 op, 938421013.00 ns, 7.1596 us/op
+WorkloadResult 3: 131072 op, 930618211.00 ns, 7.1001 us/op
+WorkloadResult 4: 131072 op, 933737942.00 ns, 7.1239 us/op
+WorkloadResult 5: 131072 op, 929592719.00 ns, 7.0922 us/op
+WorkloadResult 6: 131072 op, 927587070.00 ns, 7.0769 us/op
+WorkloadResult 7: 131072 op, 931697847.00 ns, 7.1083 us/op
+WorkloadResult 8: 131072 op, 935280169.00 ns, 7.1356 us/op
+WorkloadResult 9: 131072 op, 934519184.00 ns, 7.1298 us/op
+WorkloadResult 10: 131072 op, 931198184.00 ns, 7.1045 us/op
+WorkloadResult 11: 131072 op, 934642010.00 ns, 7.1308 us/op
+WorkloadResult 12: 131072 op, 934056284.00 ns, 7.1263 us/op
+WorkloadResult 13: 131072 op, 929662169.00 ns, 7.0928 us/op
+// GC: 62 0 0 1083179008 131072
+// Threading: 0 0 131072
+
+// AfterAll
+// Benchmark Process 254201 has exited with code 0.
+
+Mean = 7.117 μs, StdErr = 0.006 μs (0.09%), N = 13, StdDev = 0.023 μs
+Min = 7.077 μs, Q1 = 7.100 μs, Median = 7.124 μs, Q3 = 7.131 μs, Max = 7.160 μs
+IQR = 0.031 μs, LowerFence = 7.054 μs, UpperFence = 7.177 μs
+ConfidenceInterval = [7.089 μs; 7.144 μs] (CI 99.9%), Margin = 0.027 μs (0.39% of Mean)
+Skewness = 0.01, Kurtosis = 1.94, MValue = 2
+
+// ** Remained 4 (36.4 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii --job Default --benchmarkId 7 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 274834.00 ns, 274.8340 us/op
+WorkloadJitting 1: 1 op, 19553981.00 ns, 19.5540 ms/op
+
+OverheadJitting 2: 16 op, 684616.00 ns, 42.7885 us/op
+WorkloadJitting 2: 16 op, 17502226.00 ns, 1.0939 ms/op
+
+WorkloadPilot 1: 16 op, 16789613.00 ns, 1.0494 ms/op
+WorkloadPilot 2: 32 op, 33221901.00 ns, 1.0382 ms/op
+WorkloadPilot 3: 64 op, 66731137.00 ns, 1.0427 ms/op
+WorkloadPilot 4: 128 op, 127874122.00 ns, 999.0166 us/op
+WorkloadPilot 5: 256 op, 152049991.00 ns, 593.9453 us/op
+WorkloadPilot 6: 512 op, 304292349.00 ns, 594.3210 us/op
+WorkloadPilot 7: 1024 op, 607043251.00 ns, 592.8157 us/op
+
+OverheadWarmup 1: 1024 op, 7679.00 ns, 7.4990 ns/op
+OverheadWarmup 2: 1024 op, 5023.00 ns, 4.9053 ns/op
+OverheadWarmup 3: 1024 op, 4992.00 ns, 4.8750 ns/op
+OverheadWarmup 4: 1024 op, 4963.00 ns, 4.8467 ns/op
+OverheadWarmup 5: 1024 op, 5112.00 ns, 4.9922 ns/op
+OverheadWarmup 6: 1024 op, 5080.00 ns, 4.9609 ns/op
+OverheadWarmup 7: 1024 op, 4992.00 ns, 4.8750 ns/op
+OverheadWarmup 8: 1024 op, 11111.00 ns, 10.8506 ns/op
+OverheadWarmup 9: 1024 op, 4887.00 ns, 4.7725 ns/op
+
+OverheadActual 1: 1024 op, 5365.00 ns, 5.2393 ns/op
+OverheadActual 2: 1024 op, 5599.00 ns, 5.4678 ns/op
+OverheadActual 3: 1024 op, 5520.00 ns, 5.3906 ns/op
+OverheadActual 4: 1024 op, 5312.00 ns, 5.1875 ns/op
+OverheadActual 5: 1024 op, 5140.00 ns, 5.0195 ns/op
+OverheadActual 6: 1024 op, 5190.00 ns, 5.0684 ns/op
+OverheadActual 7: 1024 op, 5112.00 ns, 4.9922 ns/op
+OverheadActual 8: 1024 op, 5006.00 ns, 4.8887 ns/op
+OverheadActual 9: 1024 op, 5139.00 ns, 5.0186 ns/op
+OverheadActual 10: 1024 op, 5124.00 ns, 5.0039 ns/op
+OverheadActual 11: 1024 op, 4985.00 ns, 4.8682 ns/op
+OverheadActual 12: 1024 op, 4985.00 ns, 4.8682 ns/op
+OverheadActual 13: 1024 op, 5061.00 ns, 4.9424 ns/op
+OverheadActual 14: 1024 op, 5106.00 ns, 4.9863 ns/op
+OverheadActual 15: 1024 op, 4892.00 ns, 4.7773 ns/op
+
+WorkloadWarmup 1: 1024 op, 622055648.00 ns, 607.4762 us/op
+WorkloadWarmup 2: 1024 op, 618583581.00 ns, 604.0855 us/op
+WorkloadWarmup 3: 1024 op, 622163759.00 ns, 607.5818 us/op
+WorkloadWarmup 4: 1024 op, 608406856.00 ns, 594.1473 us/op
+WorkloadWarmup 5: 1024 op, 608759317.00 ns, 594.4915 us/op
+WorkloadWarmup 6: 1024 op, 612597377.00 ns, 598.2396 us/op
+WorkloadWarmup 7: 1024 op, 615952591.00 ns, 601.5162 us/op
+WorkloadWarmup 8: 1024 op, 610328741.00 ns, 596.0242 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 1024 op, 614300462.00 ns, 599.9028 us/op
+WorkloadActual 2: 1024 op, 609849388.00 ns, 595.5560 us/op
+WorkloadActual 3: 1024 op, 609777299.00 ns, 595.4856 us/op
+WorkloadActual 4: 1024 op, 611241482.00 ns, 596.9155 us/op
+WorkloadActual 5: 1024 op, 605642348.00 ns, 591.4476 us/op
+WorkloadActual 6: 1024 op, 608752565.00 ns, 594.4849 us/op
+WorkloadActual 7: 1024 op, 607916471.00 ns, 593.6684 us/op
+WorkloadActual 8: 1024 op, 620638257.00 ns, 606.0920 us/op
+WorkloadActual 9: 1024 op, 609141619.00 ns, 594.8649 us/op
+WorkloadActual 10: 1024 op, 606136353.00 ns, 591.9300 us/op
+WorkloadActual 11: 1024 op, 607489252.00 ns, 593.2512 us/op
+WorkloadActual 12: 1024 op, 608388396.00 ns, 594.1293 us/op
+WorkloadActual 13: 1024 op, 605666603.00 ns, 591.4713 us/op
+WorkloadActual 14: 1024 op, 607340009.00 ns, 593.1055 us/op
+WorkloadActual 15: 1024 op, 606502342.00 ns, 592.2874 us/op
+
+// AfterActualRun
+WorkloadResult 1: 1024 op, 609844264.00 ns, 595.5510 us/op
+WorkloadResult 2: 1024 op, 609772175.00 ns, 595.4806 us/op
+WorkloadResult 3: 1024 op, 611236358.00 ns, 596.9105 us/op
+WorkloadResult 4: 1024 op, 605637224.00 ns, 591.4426 us/op
+WorkloadResult 5: 1024 op, 608747441.00 ns, 594.4799 us/op
+WorkloadResult 6: 1024 op, 607911347.00 ns, 593.6634 us/op
+WorkloadResult 7: 1024 op, 609136495.00 ns, 594.8599 us/op
+WorkloadResult 8: 1024 op, 606131229.00 ns, 591.9250 us/op
+WorkloadResult 9: 1024 op, 607484128.00 ns, 593.2462 us/op
+WorkloadResult 10: 1024 op, 608383272.00 ns, 594.1243 us/op
+WorkloadResult 11: 1024 op, 605661479.00 ns, 591.4663 us/op
+WorkloadResult 12: 1024 op, 607334885.00 ns, 593.1005 us/op
+WorkloadResult 13: 1024 op, 606497218.00 ns, 592.2824 us/op
+// GC: 255 255 255 838995632 1024
+// Threading: 0 0 1024
+
+// AfterAll
+// Benchmark Process 254320 has exited with code 0.
+
+Mean = 593.733 μs, StdErr = 0.473 μs (0.08%), N = 13, StdDev = 1.704 μs
+Min = 591.443 μs, Q1 = 592.282 μs, Median = 593.663 μs, Q3 = 594.860 μs, Max = 596.911 μs
+IQR = 2.577 μs, LowerFence = 588.416 μs, UpperFence = 598.726 μs
+ConfidenceInterval = [591.693 μs; 595.774 μs] (CI 99.9%), Margin = 2.040 μs (0.34% of Mean)
+Skewness = 0.19, Kurtosis = 1.77, MValue = 2
+
+// ** Remained 3 (27.3 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 0m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Large_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Large_Mixed --job Default --benchmarkId 8 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 257208.00 ns, 257.2080 us/op
+WorkloadJitting 1: 1 op, 20190271.00 ns, 20.1903 ms/op
+
+OverheadJitting 2: 16 op, 693614.00 ns, 43.3509 us/op
+WorkloadJitting 2: 16 op, 25633155.00 ns, 1.6021 ms/op
+
+WorkloadPilot 1: 16 op, 24557161.00 ns, 1.5348 ms/op
+WorkloadPilot 2: 32 op, 49102656.00 ns, 1.5345 ms/op
+WorkloadPilot 3: 64 op, 97924581.00 ns, 1.5301 ms/op
+WorkloadPilot 4: 128 op, 151557907.00 ns, 1.1840 ms/op
+WorkloadPilot 5: 256 op, 271790083.00 ns, 1.0617 ms/op
+WorkloadPilot 6: 512 op, 543146129.00 ns, 1.0608 ms/op
+
+OverheadWarmup 1: 512 op, 7866.00 ns, 15.3633 ns/op
+OverheadWarmup 2: 512 op, 5089.00 ns, 9.9395 ns/op
+OverheadWarmup 3: 512 op, 4834.00 ns, 9.4414 ns/op
+OverheadWarmup 4: 512 op, 4804.00 ns, 9.3828 ns/op
+OverheadWarmup 5: 512 op, 5065.00 ns, 9.8926 ns/op
+OverheadWarmup 6: 512 op, 4949.00 ns, 9.6660 ns/op
+OverheadWarmup 7: 512 op, 4846.00 ns, 9.4648 ns/op
+OverheadWarmup 8: 512 op, 5037.00 ns, 9.8379 ns/op
+OverheadWarmup 9: 512 op, 4918.00 ns, 9.6055 ns/op
+
+OverheadActual 1: 512 op, 4855.00 ns, 9.4824 ns/op
+OverheadActual 2: 512 op, 5068.00 ns, 9.8984 ns/op
+OverheadActual 3: 512 op, 4947.00 ns, 9.6621 ns/op
+OverheadActual 4: 512 op, 4845.00 ns, 9.4629 ns/op
+OverheadActual 5: 512 op, 4902.00 ns, 9.5742 ns/op
+OverheadActual 6: 512 op, 5048.00 ns, 9.8594 ns/op
+OverheadActual 7: 512 op, 4840.00 ns, 9.4531 ns/op
+OverheadActual 8: 512 op, 4853.00 ns, 9.4785 ns/op
+OverheadActual 9: 512 op, 4870.00 ns, 9.5117 ns/op
+OverheadActual 10: 512 op, 4914.00 ns, 9.5977 ns/op
+OverheadActual 11: 512 op, 4789.00 ns, 9.3535 ns/op
+OverheadActual 12: 512 op, 4886.00 ns, 9.5430 ns/op
+OverheadActual 13: 512 op, 33867.00 ns, 66.1465 ns/op
+OverheadActual 14: 512 op, 5051.00 ns, 9.8652 ns/op
+OverheadActual 15: 512 op, 4731.00 ns, 9.2402 ns/op
+
+WorkloadWarmup 1: 512 op, 545408184.00 ns, 1.0653 ms/op
+WorkloadWarmup 2: 512 op, 542895216.00 ns, 1.0603 ms/op
+WorkloadWarmup 3: 512 op, 542692382.00 ns, 1.0599 ms/op
+WorkloadWarmup 4: 512 op, 538973211.00 ns, 1.0527 ms/op
+WorkloadWarmup 5: 512 op, 541813503.00 ns, 1.0582 ms/op
+WorkloadWarmup 6: 512 op, 546240569.00 ns, 1.0669 ms/op
+WorkloadWarmup 7: 512 op, 545703950.00 ns, 1.0658 ms/op
+WorkloadWarmup 8: 512 op, 544913266.00 ns, 1.0643 ms/op
+WorkloadWarmup 9: 512 op, 541987161.00 ns, 1.0586 ms/op
+WorkloadWarmup 10: 512 op, 543752942.00 ns, 1.0620 ms/op
+WorkloadWarmup 11: 512 op, 542351610.00 ns, 1.0593 ms/op
+
+// BeforeActualRun
+WorkloadActual 1: 512 op, 547947591.00 ns, 1.0702 ms/op
+WorkloadActual 2: 512 op, 547442726.00 ns, 1.0692 ms/op
+WorkloadActual 3: 512 op, 543752765.00 ns, 1.0620 ms/op
+WorkloadActual 4: 512 op, 550238240.00 ns, 1.0747 ms/op
+WorkloadActual 5: 512 op, 547205106.00 ns, 1.0688 ms/op
+WorkloadActual 6: 512 op, 545069360.00 ns, 1.0646 ms/op
+WorkloadActual 7: 512 op, 541841753.00 ns, 1.0583 ms/op
+WorkloadActual 8: 512 op, 541530211.00 ns, 1.0577 ms/op
+WorkloadActual 9: 512 op, 543501000.00 ns, 1.0615 ms/op
+WorkloadActual 10: 512 op, 546091303.00 ns, 1.0666 ms/op
+WorkloadActual 11: 512 op, 539739605.00 ns, 1.0542 ms/op
+WorkloadActual 12: 512 op, 543230659.00 ns, 1.0610 ms/op
+WorkloadActual 13: 512 op, 544861076.00 ns, 1.0642 ms/op
+WorkloadActual 14: 512 op, 553753717.00 ns, 1.0816 ms/op
+WorkloadActual 15: 512 op, 553032455.00 ns, 1.0801 ms/op
+
+// AfterActualRun
+WorkloadResult 1: 512 op, 547942705.00 ns, 1.0702 ms/op
+WorkloadResult 2: 512 op, 547437840.00 ns, 1.0692 ms/op
+WorkloadResult 3: 512 op, 543747879.00 ns, 1.0620 ms/op
+WorkloadResult 4: 512 op, 550233354.00 ns, 1.0747 ms/op
+WorkloadResult 5: 512 op, 547200220.00 ns, 1.0688 ms/op
+WorkloadResult 6: 512 op, 545064474.00 ns, 1.0646 ms/op
+WorkloadResult 7: 512 op, 541836867.00 ns, 1.0583 ms/op
+WorkloadResult 8: 512 op, 541525325.00 ns, 1.0577 ms/op
+WorkloadResult 9: 512 op, 543496114.00 ns, 1.0615 ms/op
+WorkloadResult 10: 512 op, 546086417.00 ns, 1.0666 ms/op
+WorkloadResult 11: 512 op, 539734719.00 ns, 1.0542 ms/op
+WorkloadResult 12: 512 op, 543225773.00 ns, 1.0610 ms/op
+WorkloadResult 13: 512 op, 544856190.00 ns, 1.0642 ms/op
+WorkloadResult 14: 512 op, 553748831.00 ns, 1.0815 ms/op
+WorkloadResult 15: 512 op, 553027569.00 ns, 1.0801 ms/op
+// GC: 127 127 127 421643952 512
+// Threading: 0 0 512
+
+// AfterAll
+// Benchmark Process 254371 has exited with code 0.
+
+Mean = 1.066 ms, StdErr = 0.002 ms (0.19%), N = 15, StdDev = 0.008 ms
+Min = 1.054 ms, Q1 = 1.061 ms, Median = 1.065 ms, Q3 = 1.070 ms, Max = 1.082 ms
+IQR = 0.008 ms, LowerFence = 1.049 ms, UpperFence = 1.082 ms
+ConfidenceInterval = [1.058 ms; 1.075 ms] (CI 99.9%), Margin = 0.009 ms (0.80% of Mean)
+Skewness = 0.47, Kurtosis = 2.14, MValue = 2
+
+// ** Remained 2 (18.2 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 0m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase --job Default --benchmarkId 9 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 313082.00 ns, 313.0820 us/op
+WorkloadJitting 1: 1 op, 21634822.00 ns, 21.6348 ms/op
+
+OverheadJitting 2: 16 op, 669818.00 ns, 41.8636 us/op
+WorkloadJitting 2: 16 op, 45092801.00 ns, 2.8183 ms/op
+
+WorkloadPilot 1: 16 op, 43479942.00 ns, 2.7175 ms/op
+WorkloadPilot 2: 32 op, 85947936.00 ns, 2.6859 ms/op
+WorkloadPilot 3: 64 op, 159423635.00 ns, 2.4910 ms/op
+WorkloadPilot 4: 128 op, 296554642.00 ns, 2.3168 ms/op
+WorkloadPilot 5: 256 op, 566389270.00 ns, 2.2125 ms/op
+
+OverheadWarmup 1: 256 op, 4347.00 ns, 16.9805 ns/op
+OverheadWarmup 2: 256 op, 1905.00 ns, 7.4414 ns/op
+OverheadWarmup 3: 256 op, 1727.00 ns, 6.7461 ns/op
+OverheadWarmup 4: 256 op, 1691.00 ns, 6.6055 ns/op
+OverheadWarmup 5: 256 op, 1944.00 ns, 7.5938 ns/op
+OverheadWarmup 6: 256 op, 1718.00 ns, 6.7109 ns/op
+OverheadWarmup 7: 256 op, 1720.00 ns, 6.7188 ns/op
+OverheadWarmup 8: 256 op, 1742.00 ns, 6.8047 ns/op
+OverheadWarmup 9: 256 op, 1638.00 ns, 6.3984 ns/op
+
+OverheadActual 1: 256 op, 1953.00 ns, 7.6289 ns/op
+OverheadActual 2: 256 op, 1984.00 ns, 7.7500 ns/op
+OverheadActual 3: 256 op, 1948.00 ns, 7.6094 ns/op
+OverheadActual 4: 256 op, 1768.00 ns, 6.9063 ns/op
+OverheadActual 5: 256 op, 1779.00 ns, 6.9492 ns/op
+OverheadActual 6: 256 op, 1776.00 ns, 6.9375 ns/op
+OverheadActual 7: 256 op, 1731.00 ns, 6.7617 ns/op
+OverheadActual 8: 256 op, 1715.00 ns, 6.6992 ns/op
+OverheadActual 9: 256 op, 1757.00 ns, 6.8633 ns/op
+OverheadActual 10: 256 op, 3758.00 ns, 14.6797 ns/op
+OverheadActual 11: 256 op, 1698.00 ns, 6.6328 ns/op
+OverheadActual 12: 256 op, 1740.00 ns, 6.7969 ns/op
+OverheadActual 13: 256 op, 1763.00 ns, 6.8867 ns/op
+OverheadActual 14: 256 op, 1651.00 ns, 6.4492 ns/op
+OverheadActual 15: 256 op, 1663.00 ns, 6.4961 ns/op
+OverheadActual 16: 256 op, 1814.00 ns, 7.0859 ns/op
+OverheadActual 17: 256 op, 1790.00 ns, 6.9922 ns/op
+
+WorkloadWarmup 1: 256 op, 549721634.00 ns, 2.1474 ms/op
+WorkloadWarmup 2: 256 op, 551086613.00 ns, 2.1527 ms/op
+WorkloadWarmup 3: 256 op, 544079531.00 ns, 2.1253 ms/op
+WorkloadWarmup 4: 256 op, 548134918.00 ns, 2.1412 ms/op
+WorkloadWarmup 5: 256 op, 545042876.00 ns, 2.1291 ms/op
+WorkloadWarmup 6: 256 op, 550140035.00 ns, 2.1490 ms/op
+
+// BeforeActualRun
+WorkloadActual 1: 256 op, 538742680.00 ns, 2.1045 ms/op
+WorkloadActual 2: 256 op, 549487716.00 ns, 2.1464 ms/op
+WorkloadActual 3: 256 op, 553393058.00 ns, 2.1617 ms/op
+WorkloadActual 4: 256 op, 553765603.00 ns, 2.1631 ms/op
+WorkloadActual 5: 256 op, 551305227.00 ns, 2.1535 ms/op
+WorkloadActual 6: 256 op, 551180807.00 ns, 2.1531 ms/op
+WorkloadActual 7: 256 op, 548904414.00 ns, 2.1442 ms/op
+WorkloadActual 8: 256 op, 548085684.00 ns, 2.1410 ms/op
+WorkloadActual 9: 256 op, 547606847.00 ns, 2.1391 ms/op
+WorkloadActual 10: 256 op, 550185065.00 ns, 2.1492 ms/op
+WorkloadActual 11: 256 op, 548309754.00 ns, 2.1418 ms/op
+WorkloadActual 12: 256 op, 551423386.00 ns, 2.1540 ms/op
+WorkloadActual 13: 256 op, 556245137.00 ns, 2.1728 ms/op
+WorkloadActual 14: 256 op, 552063900.00 ns, 2.1565 ms/op
+WorkloadActual 15: 256 op, 548298345.00 ns, 2.1418 ms/op
+
+// AfterActualRun
+WorkloadResult 1: 256 op, 538740912.00 ns, 2.1045 ms/op
+WorkloadResult 2: 256 op, 549485948.00 ns, 2.1464 ms/op
+WorkloadResult 3: 256 op, 553391290.00 ns, 2.1617 ms/op
+WorkloadResult 4: 256 op, 553763835.00 ns, 2.1631 ms/op
+WorkloadResult 5: 256 op, 551303459.00 ns, 2.1535 ms/op
+WorkloadResult 6: 256 op, 551179039.00 ns, 2.1530 ms/op
+WorkloadResult 7: 256 op, 548902646.00 ns, 2.1442 ms/op
+WorkloadResult 8: 256 op, 548083916.00 ns, 2.1410 ms/op
+WorkloadResult 9: 256 op, 547605079.00 ns, 2.1391 ms/op
+WorkloadResult 10: 256 op, 550183297.00 ns, 2.1492 ms/op
+WorkloadResult 11: 256 op, 548307986.00 ns, 2.1418 ms/op
+WorkloadResult 12: 256 op, 551421618.00 ns, 2.1540 ms/op
+WorkloadResult 13: 256 op, 556243369.00 ns, 2.1728 ms/op
+WorkloadResult 14: 256 op, 552062132.00 ns, 2.1565 ms/op
+WorkloadResult 15: 256 op, 548296577.00 ns, 2.1418 ms/op
+// GC: 63 63 63 262175944 256
+// Threading: 0 0 256
+
+// AfterAll
+// Benchmark Process 254455 has exited with code 0.
+
+Mean = 2.148 ms, StdErr = 0.004 ms (0.19%), N = 15, StdDev = 0.015 ms
+Min = 2.104 ms, Q1 = 2.142 ms, Median = 2.149 ms, Q3 = 2.155 ms, Max = 2.173 ms
+IQR = 0.013 ms, LowerFence = 2.122 ms, UpperFence = 2.175 ms
+ConfidenceInterval = [2.132 ms; 2.165 ms] (CI 99.9%), Margin = 0.016 ms (0.77% of Mean)
+Skewness = -1.16, Kurtosis = 4.9, MValue = 2
+
+// ** Remained 1 (9.1 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 0m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBaselineBenchmarks.CharArray_Medium_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-Job-RELKCN-1.dll --anonymousPipes 129 130 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks.CharArray_Medium_Mixed --job Default --benchmarkId 10 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-Job-RELKCN-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 279823.00 ns, 279.8230 us/op
+WorkloadJitting 1: 1 op, 18282345.00 ns, 18.2823 ms/op
+
+OverheadJitting 2: 16 op, 707901.00 ns, 44.2438 us/op
+WorkloadJitting 2: 16 op, 1898599.00 ns, 118.6624 us/op
+
+WorkloadPilot 1: 16 op, 621650.00 ns, 38.8531 us/op
+WorkloadPilot 2: 32 op, 1247899.00 ns, 38.9968 us/op
+WorkloadPilot 3: 64 op, 2135377.00 ns, 33.3653 us/op
+WorkloadPilot 4: 128 op, 4204836.00 ns, 32.8503 us/op
+WorkloadPilot 5: 256 op, 8410378.00 ns, 32.8530 us/op
+WorkloadPilot 6: 512 op, 16410750.00 ns, 32.0522 us/op
+WorkloadPilot 7: 1024 op, 32283014.00 ns, 31.5264 us/op
+WorkloadPilot 8: 2048 op, 66809847.00 ns, 32.6220 us/op
+WorkloadPilot 9: 4096 op, 38166393.00 ns, 9.3180 us/op
+WorkloadPilot 10: 8192 op, 61253805.00 ns, 7.4773 us/op
+WorkloadPilot 11: 16384 op, 120265624.00 ns, 7.3404 us/op
+WorkloadPilot 12: 32768 op, 242691632.00 ns, 7.4064 us/op
+WorkloadPilot 13: 65536 op, 484365130.00 ns, 7.3908 us/op
+WorkloadPilot 14: 131072 op, 957404429.00 ns, 7.3044 us/op
+
+OverheadWarmup 1: 131072 op, 613324.00 ns, 4.6793 ns/op
+OverheadWarmup 2: 131072 op, 644641.00 ns, 4.9182 ns/op
+OverheadWarmup 3: 131072 op, 635525.00 ns, 4.8487 ns/op
+OverheadWarmup 4: 131072 op, 611724.00 ns, 4.6671 ns/op
+OverheadWarmup 5: 131072 op, 611359.00 ns, 4.6643 ns/op
+OverheadWarmup 6: 131072 op, 626682.00 ns, 4.7812 ns/op
+OverheadWarmup 7: 131072 op, 635203.00 ns, 4.8462 ns/op
+OverheadWarmup 8: 131072 op, 611169.00 ns, 4.6628 ns/op
+
+OverheadActual 1: 131072 op, 628645.00 ns, 4.7962 ns/op
+OverheadActual 2: 131072 op, 612012.00 ns, 4.6693 ns/op
+OverheadActual 3: 131072 op, 616951.00 ns, 4.7070 ns/op
+OverheadActual 4: 131072 op, 611571.00 ns, 4.6659 ns/op
+OverheadActual 5: 131072 op, 633962.00 ns, 4.8367 ns/op
+OverheadActual 6: 131072 op, 611169.00 ns, 4.6628 ns/op
+OverheadActual 7: 131072 op, 611089.00 ns, 4.6622 ns/op
+OverheadActual 8: 131072 op, 634504.00 ns, 4.8409 ns/op
+OverheadActual 9: 131072 op, 630964.00 ns, 4.8139 ns/op
+OverheadActual 10: 131072 op, 657774.00 ns, 5.0184 ns/op
+OverheadActual 11: 131072 op, 663245.00 ns, 5.0602 ns/op
+OverheadActual 12: 131072 op, 631976.00 ns, 4.8216 ns/op
+OverheadActual 13: 131072 op, 666106.00 ns, 5.0820 ns/op
+OverheadActual 14: 131072 op, 649052.00 ns, 4.9519 ns/op
+OverheadActual 15: 131072 op, 678249.00 ns, 5.1746 ns/op
+
+WorkloadWarmup 1: 131072 op, 969706959.00 ns, 7.3983 us/op
+WorkloadWarmup 2: 131072 op, 963962539.00 ns, 7.3545 us/op
+WorkloadWarmup 3: 131072 op, 963728843.00 ns, 7.3527 us/op
+WorkloadWarmup 4: 131072 op, 953981377.00 ns, 7.2783 us/op
+WorkloadWarmup 5: 131072 op, 963333178.00 ns, 7.3496 us/op
+WorkloadWarmup 6: 131072 op, 961160951.00 ns, 7.3331 us/op
+WorkloadWarmup 7: 131072 op, 958028379.00 ns, 7.3092 us/op
+WorkloadWarmup 8: 131072 op, 958298866.00 ns, 7.3112 us/op
+WorkloadWarmup 9: 131072 op, 946635871.00 ns, 7.2223 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 131072 op, 953863340.00 ns, 7.2774 us/op
+WorkloadActual 2: 131072 op, 967223388.00 ns, 7.3793 us/op
+WorkloadActual 3: 131072 op, 969141888.00 ns, 7.3940 us/op
+WorkloadActual 4: 131072 op, 975349856.00 ns, 7.4413 us/op
+WorkloadActual 5: 131072 op, 959701161.00 ns, 7.3219 us/op
+WorkloadActual 6: 131072 op, 969138342.00 ns, 7.3939 us/op
+WorkloadActual 7: 131072 op, 956372516.00 ns, 7.2965 us/op
+WorkloadActual 8: 131072 op, 965916589.00 ns, 7.3694 us/op
+WorkloadActual 9: 131072 op, 966172594.00 ns, 7.3713 us/op
+WorkloadActual 10: 131072 op, 967313363.00 ns, 7.3800 us/op
+WorkloadActual 11: 131072 op, 977443144.00 ns, 7.4573 us/op
+WorkloadActual 12: 131072 op, 972482409.00 ns, 7.4195 us/op
+WorkloadActual 13: 131072 op, 960445326.00 ns, 7.3276 us/op
+WorkloadActual 14: 131072 op, 958933141.00 ns, 7.3161 us/op
+WorkloadActual 15: 131072 op, 954913908.00 ns, 7.2854 us/op
+
+// AfterActualRun
+WorkloadResult 1: 131072 op, 953231364.00 ns, 7.2726 us/op
+WorkloadResult 2: 131072 op, 966591412.00 ns, 7.3745 us/op
+WorkloadResult 3: 131072 op, 968509912.00 ns, 7.3891 us/op
+WorkloadResult 4: 131072 op, 974717880.00 ns, 7.4365 us/op
+WorkloadResult 5: 131072 op, 959069185.00 ns, 7.3171 us/op
+WorkloadResult 6: 131072 op, 968506366.00 ns, 7.3891 us/op
+WorkloadResult 7: 131072 op, 955740540.00 ns, 7.2917 us/op
+WorkloadResult 8: 131072 op, 965284613.00 ns, 7.3645 us/op
+WorkloadResult 9: 131072 op, 965540618.00 ns, 7.3665 us/op
+WorkloadResult 10: 131072 op, 966681387.00 ns, 7.3752 us/op
+WorkloadResult 11: 131072 op, 976811168.00 ns, 7.4525 us/op
+WorkloadResult 12: 131072 op, 971850433.00 ns, 7.4146 us/op
+WorkloadResult 13: 131072 op, 959813350.00 ns, 7.3228 us/op
+WorkloadResult 14: 131072 op, 958301165.00 ns, 7.3113 us/op
+WorkloadResult 15: 131072 op, 954281932.00 ns, 7.2806 us/op
+// GC: 78 1 0 1354760192 131072
+// Threading: 0 0 131072
+
+// AfterAll
+// Benchmark Process 254507 has exited with code 0.
+
+Mean = 7.357 μs, StdErr = 0.014 μs (0.20%), N = 15, StdDev = 0.056 μs
+Min = 7.273 μs, Q1 = 7.314 μs, Median = 7.366 μs, Q3 = 7.389 μs, Max = 7.452 μs
+IQR = 0.075 μs, LowerFence = 7.202 μs, UpperFence = 7.502 μs
+ConfidenceInterval = [7.298 μs; 7.417 μs] (CI 99.9%), Margin = 0.060 μs (0.81% of Mean)
+Skewness = 0.03, Kurtosis = 1.7, MValue = 2
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-12 23:10 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.html
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-default.md
+
+// * Detailed results *
+Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 82.813 ns, StdErr = 0.091 ns (0.11%), N = 12, StdDev = 0.314 ns
+Min = 82.361 ns, Q1 = 82.622 ns, Median = 82.885 ns, Q3 = 83.009 ns, Max = 83.439 ns
+IQR = 0.388 ns, LowerFence = 82.040 ns, UpperFence = 83.591 ns
+ConfidenceInterval = [82.411 ns; 83.216 ns] (CI 99.9%), Margin = 0.402 ns (0.49% of Mean)
+Skewness = 0.16, Kurtosis = 2.13, MValue = 2
+-------------------- Histogram --------------------
+[82.181 ns ; 83.619 ns) | @@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 71.047 ns, StdErr = 0.051 ns (0.07%), N = 12, StdDev = 0.176 ns
+Min = 70.875 ns, Q1 = 70.887 ns, Median = 70.993 ns, Q3 = 71.207 ns, Max = 71.314 ns
+IQR = 0.321 ns, LowerFence = 70.406 ns, UpperFence = 71.688 ns
+ConfidenceInterval = [70.822 ns; 71.272 ns] (CI 99.9%), Margin = 0.225 ns (0.32% of Mean)
+Skewness = 0.48, Kurtosis = 1.4, MValue = 2
+-------------------- Histogram --------------------
+[70.775 ns ; 71.414 ns) | @@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 695.745 ns, StdErr = 1.018 ns (0.15%), N = 13, StdDev = 3.669 ns
+Min = 692.091 ns, Q1 = 693.946 ns, Median = 694.394 ns, Q3 = 695.911 ns, Max = 704.611 ns
+IQR = 1.965 ns, LowerFence = 690.998 ns, UpperFence = 698.858 ns
+ConfidenceInterval = [691.352 ns; 700.139 ns] (CI 99.9%), Margin = 4.394 ns (0.63% of Mean)
+Skewness = 1.43, Kurtosis = 3.65, MValue = 2
+-------------------- Histogram --------------------
+[690.043 ns ; 706.659 ns) | @@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Small_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 686.542 ns, StdErr = 2.142 ns (0.31%), N = 15, StdDev = 8.295 ns
+Min = 677.863 ns, Q1 = 679.613 ns, Median = 680.511 ns, Q3 = 695.387 ns, Max = 698.465 ns
+IQR = 15.774 ns, LowerFence = 655.953 ns, UpperFence = 719.048 ns
+ConfidenceInterval = [677.674 ns; 695.410 ns] (CI 99.9%), Margin = 8.868 ns (1.29% of Mean)
+Skewness = 0.22, Kurtosis = 1.07, MValue = 2
+-------------------- Histogram --------------------
+[673.448 ns ; 702.880 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 5.995 μs, StdErr = 0.008 μs (0.13%), N = 15, StdDev = 0.031 μs
+Min = 5.932 μs, Q1 = 5.982 μs, Median = 5.990 μs, Q3 = 6.015 μs, Max = 6.044 μs
+IQR = 0.033 μs, LowerFence = 5.933 μs, UpperFence = 6.064 μs
+ConfidenceInterval = [5.962 μs; 6.028 μs] (CI 99.9%), Margin = 0.033 μs (0.55% of Mean)
+Skewness = -0.24, Kurtosis = 2.22, MValue = 2
+-------------------- Histogram --------------------
+[5.916 μs ; 6.061 μs) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 7.117 μs, StdErr = 0.006 μs (0.09%), N = 13, StdDev = 0.023 μs
+Min = 7.077 μs, Q1 = 7.100 μs, Median = 7.124 μs, Q3 = 7.131 μs, Max = 7.160 μs
+IQR = 0.031 μs, LowerFence = 7.054 μs, UpperFence = 7.177 μs
+ConfidenceInterval = [7.089 μs; 7.144 μs] (CI 99.9%), Margin = 0.027 μs (0.39% of Mean)
+Skewness = 0.01, Kurtosis = 1.94, MValue = 2
+-------------------- Histogram --------------------
+[7.064 μs ; 7.172 μs) | @@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 593.733 μs, StdErr = 0.473 μs (0.08%), N = 13, StdDev = 1.704 μs
+Min = 591.443 μs, Q1 = 592.282 μs, Median = 593.663 μs, Q3 = 594.860 μs, Max = 596.911 μs
+IQR = 2.577 μs, LowerFence = 588.416 μs, UpperFence = 598.726 μs
+ConfidenceInterval = [591.693 μs; 595.774 μs] (CI 99.9%), Margin = 2.040 μs (0.34% of Mean)
+Skewness = 0.19, Kurtosis = 1.77, MValue = 2
+-------------------- Histogram --------------------
+[590.492 μs ; 597.862 μs) | @@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Large_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 1.066 ms, StdErr = 0.002 ms (0.19%), N = 15, StdDev = 0.008 ms
+Min = 1.054 ms, Q1 = 1.061 ms, Median = 1.065 ms, Q3 = 1.070 ms, Max = 1.082 ms
+IQR = 0.008 ms, LowerFence = 1.049 ms, UpperFence = 1.082 ms
+ConfidenceInterval = [1.058 ms; 1.075 ms] (CI 99.9%), Margin = 0.009 ms (0.80% of Mean)
+Skewness = 0.47, Kurtosis = 2.14, MValue = 2
+-------------------- Histogram --------------------
+[1.050 ms ; 1.086 ms) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 2.148 ms, StdErr = 0.004 ms (0.19%), N = 15, StdDev = 0.015 ms
+Min = 2.104 ms, Q1 = 2.142 ms, Median = 2.149 ms, Q3 = 2.155 ms, Max = 2.173 ms
+IQR = 0.013 ms, LowerFence = 2.122 ms, UpperFence = 2.175 ms
+ConfidenceInterval = [2.132 ms; 2.165 ms] (CI 99.9%), Margin = 0.016 ms (0.77% of Mean)
+Skewness = -1.16, Kurtosis = 4.9, MValue = 2
+-------------------- Histogram --------------------
+[2.096 ms ; 2.181 ms) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBaselineBenchmarks.CharArray_Medium_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 7.357 μs, StdErr = 0.014 μs (0.20%), N = 15, StdDev = 0.056 μs
+Min = 7.273 μs, Q1 = 7.314 μs, Median = 7.366 μs, Q3 = 7.389 μs, Max = 7.452 μs
+IQR = 0.075 μs, LowerFence = 7.202 μs, UpperFence = 7.502 μs
+ConfidenceInterval = [7.298 μs; 7.417 μs] (CI 99.9%), Margin = 0.060 μs (0.81% of Mean)
+Skewness = 0.03, Kurtosis = 1.7, MValue = 2
+-------------------- Histogram --------------------
+[7.243 μs ; 7.463 μs) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+|----------------------- |----------------:|--------------:|--------------:|-----:|---------:|---------:|---------:|----------:|
+| Tiny_Ascii | 82.81 ns | 0.402 ns | 0.314 ns | 2 | 0.0027 | - | - | 48 B |
+| Tiny_Mixed | 71.05 ns | 0.225 ns | 0.176 ns | 1 | 0.0027 | - | - | 48 B |
+| Small_Ascii | 695.75 ns | 4.394 ns | 3.669 ns | 3 | 0.0124 | - | - | 224 B |
+| Small_Mixed | 686.54 ns | 8.868 ns | 8.295 ns | 3 | 0.0124 | - | - | 224 B |
+| Medium_Ascii | 5,994.68 ns | 32.905 ns | 30.779 ns | 4 | 0.4730 | - | - | 8240 B |
+| Medium_Mixed | 7,116.65 ns | 27.489 ns | 22.955 ns | 5 | 0.4730 | - | - | 8264 B |
+| Large_Ascii | 593,733.29 ns | 2,040.378 ns | 1,703.808 ns | 7 | 249.0234 | 249.0234 | 249.0234 | 819332 B |
+| Large_Mixed | 1,066,297.43 ns | 8,507.650 ns | 7,958.061 ns | 8 | 248.0469 | 248.0469 | 248.0469 | 823523 B |
+| Large_WorstCase | 2,148,169.56 ns | 16,455.374 ns | 15,392.367 ns | 9 | 246.0938 | 246.0938 | 246.0938 | 1024125 B |
+| CharArray_Medium_Mixed | 7,357.24 ns | 59.719 ns | 55.861 ns | 6 | 0.5951 | 0.0076 | - | 10336 B |
+
+// * Hints *
+Outliers
+ Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Ascii: Default -> 3 outliers were removed (88.26 ns..89.11 ns)
+ Utf8ToAsciiConverterBaselineBenchmarks.Tiny_Mixed: Default -> 3 outliers were removed (76.73 ns..77.20 ns)
+ Utf8ToAsciiConverterBaselineBenchmarks.Small_Ascii: Default -> 2 outliers were removed (712.12 ns, 713.89 ns)
+ Utf8ToAsciiConverterBaselineBenchmarks.Medium_Ascii: Default -> 1 outlier was detected (5.94 μs)
+ Utf8ToAsciiConverterBaselineBenchmarks.Medium_Mixed: Default -> 2 outliers were removed (7.24 μs, 7.27 μs)
+ Utf8ToAsciiConverterBaselineBenchmarks.Large_Ascii: Default -> 2 outliers were removed (599.90 μs, 606.09 μs)
+ Utf8ToAsciiConverterBaselineBenchmarks.Large_WorstCase: Default -> 1 outlier was detected (2.10 ms)
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Rank : Relative position of current benchmark mean among all benchmarks (Arabic style)
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Gen1 : GC Generation 1 collects per 1000 operations
+ Gen2 : GC Generation 2 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:03:25 (205.38 sec), executed benchmarks: 10
+
+Global total time: 00:05:04 (304.53 sec), executed benchmarks: 11
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-213627.log b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-213627.log
new file mode 100644
index 0000000000..b94bf0a569
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-213627.log
@@ -0,0 +1,1176 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 11 benchmark(s) in total *****
+// ***** Building 1 exe(s) in Parallel: Start *****
+// start dotnet restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 4.02 sec and exited with 0
+// start dotnet build -c Release --no-restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" --output "/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 96.92 sec and exited with 0
+// ***** Done, took 00:01:41 (101.22 sec) *****
+// Found 11 benchmarks:
+// StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+// **************************
+// Benchmark: StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.Linq --job ShortRun --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 236472.00 ns, 236.4720 us/op
+WorkloadJitting 1: 1 op, 9147134.00 ns, 9.1471 ms/op
+
+OverheadJitting 2: 16 op, 516516.00 ns, 32.2823 us/op
+WorkloadJitting 2: 16 op, 3438616.00 ns, 214.9135 us/op
+
+WorkloadPilot 1: 16 op, 2838250.00 ns, 177.3906 us/op
+WorkloadPilot 2: 32 op, 5299402.00 ns, 165.6063 us/op
+WorkloadPilot 3: 64 op, 11246416.00 ns, 175.7253 us/op
+WorkloadPilot 4: 128 op, 22545619.00 ns, 176.1376 us/op
+WorkloadPilot 5: 256 op, 45059825.00 ns, 176.0149 us/op
+WorkloadPilot 6: 512 op, 98879334.00 ns, 193.1237 us/op
+WorkloadPilot 7: 1024 op, 53859003.00 ns, 52.5967 us/op
+WorkloadPilot 8: 2048 op, 103216550.00 ns, 50.3987 us/op
+WorkloadPilot 9: 4096 op, 206182712.00 ns, 50.3376 us/op
+WorkloadPilot 10: 8192 op, 409068039.00 ns, 49.9351 us/op
+WorkloadPilot 11: 16384 op, 819111274.00 ns, 49.9946 us/op
+
+OverheadWarmup 1: 16384 op, 62040.00 ns, 3.7866 ns/op
+OverheadWarmup 2: 16384 op, 69014.00 ns, 4.2123 ns/op
+OverheadWarmup 3: 16384 op, 69501.00 ns, 4.2420 ns/op
+OverheadWarmup 4: 16384 op, 68248.00 ns, 4.1655 ns/op
+OverheadWarmup 5: 16384 op, 63133.00 ns, 3.8533 ns/op
+OverheadWarmup 6: 16384 op, 69223.00 ns, 4.2250 ns/op
+OverheadWarmup 7: 16384 op, 70234.00 ns, 4.2867 ns/op
+OverheadWarmup 8: 16384 op, 69801.00 ns, 4.2603 ns/op
+
+OverheadActual 1: 16384 op, 69727.00 ns, 4.2558 ns/op
+OverheadActual 2: 16384 op, 63650.00 ns, 3.8849 ns/op
+OverheadActual 3: 16384 op, 59558.00 ns, 3.6351 ns/op
+OverheadActual 4: 16384 op, 61898.00 ns, 3.7780 ns/op
+OverheadActual 5: 16384 op, 68255.00 ns, 4.1660 ns/op
+OverheadActual 6: 16384 op, 86284.00 ns, 5.2664 ns/op
+OverheadActual 7: 16384 op, 69871.00 ns, 4.2646 ns/op
+OverheadActual 8: 16384 op, 70038.00 ns, 4.2748 ns/op
+OverheadActual 9: 16384 op, 71433.00 ns, 4.3599 ns/op
+OverheadActual 10: 16384 op, 71179.00 ns, 4.3444 ns/op
+OverheadActual 11: 16384 op, 68614.00 ns, 4.1879 ns/op
+OverheadActual 12: 16384 op, 68659.00 ns, 4.1906 ns/op
+OverheadActual 13: 16384 op, 71951.00 ns, 4.3915 ns/op
+OverheadActual 14: 16384 op, 70018.00 ns, 4.2736 ns/op
+OverheadActual 15: 16384 op, 74959.00 ns, 4.5751 ns/op
+OverheadActual 16: 16384 op, 63813.00 ns, 3.8948 ns/op
+OverheadActual 17: 16384 op, 66788.00 ns, 4.0764 ns/op
+OverheadActual 18: 16384 op, 59962.00 ns, 3.6598 ns/op
+OverheadActual 19: 16384 op, 69844.00 ns, 4.2629 ns/op
+OverheadActual 20: 16384 op, 69526.00 ns, 4.2435 ns/op
+
+WorkloadWarmup 1: 16384 op, 817921929.00 ns, 49.9220 us/op
+WorkloadWarmup 2: 16384 op, 818250016.00 ns, 49.9420 us/op
+WorkloadWarmup 3: 16384 op, 803856589.00 ns, 49.0635 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 814386938.00 ns, 49.7062 us/op
+WorkloadActual 2: 16384 op, 826491068.00 ns, 50.4450 us/op
+WorkloadActual 3: 16384 op, 822795843.00 ns, 50.2195 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 814317311.50 ns, 49.7020 us/op
+WorkloadResult 2: 16384 op, 826421441.50 ns, 50.4408 us/op
+WorkloadResult 3: 16384 op, 822726216.50 ns, 50.2152 us/op
+// GC: 56 0 0 978321408 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 381843 has exited with code 0.
+
+Mean = 50.119 μs, StdErr = 0.219 μs (0.44%), N = 3, StdDev = 0.379 μs
+Min = 49.702 μs, Q1 = 49.959 μs, Median = 50.215 μs, Q3 = 50.328 μs, Max = 50.441 μs
+IQR = 0.369 μs, LowerFence = 49.405 μs, UpperFence = 50.882 μs
+ConfidenceInterval = [43.212 μs; 57.027 μs] (CI 99.9%), Margin = 6.907 μs (13.78% of Mean)
+Skewness = -0.24, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 10 (90.9 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToHeapStrings --job ShortRun --benchmarkId 1 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 228397.00 ns, 228.3970 us/op
+WorkloadJitting 1: 1 op, 2870091.00 ns, 2.8701 ms/op
+
+OverheadJitting 2: 16 op, 494772.00 ns, 30.9233 us/op
+WorkloadJitting 2: 16 op, 1853573.00 ns, 115.8483 us/op
+
+WorkloadPilot 1: 16 op, 1348512.00 ns, 84.2820 us/op
+WorkloadPilot 2: 32 op, 2465952.00 ns, 77.0610 us/op
+WorkloadPilot 3: 64 op, 5171009.00 ns, 80.7970 us/op
+WorkloadPilot 4: 128 op, 10310875.00 ns, 80.5537 us/op
+WorkloadPilot 5: 256 op, 20530555.00 ns, 80.1975 us/op
+WorkloadPilot 6: 512 op, 35070776.00 ns, 68.4976 us/op
+WorkloadPilot 7: 1024 op, 80200241.00 ns, 78.3205 us/op
+WorkloadPilot 8: 2048 op, 80602682.00 ns, 39.3568 us/op
+WorkloadPilot 9: 4096 op, 142508005.00 ns, 34.7920 us/op
+WorkloadPilot 10: 8192 op, 292715003.00 ns, 35.7318 us/op
+WorkloadPilot 11: 16384 op, 573538650.00 ns, 35.0060 us/op
+
+OverheadWarmup 1: 16384 op, 44760.00 ns, 2.7319 ns/op
+OverheadWarmup 2: 16384 op, 41477.00 ns, 2.5316 ns/op
+OverheadWarmup 3: 16384 op, 41418.00 ns, 2.5280 ns/op
+OverheadWarmup 4: 16384 op, 41440.00 ns, 2.5293 ns/op
+OverheadWarmup 5: 16384 op, 47230.00 ns, 2.8827 ns/op
+OverheadWarmup 6: 16384 op, 41485.00 ns, 2.5320 ns/op
+OverheadWarmup 7: 16384 op, 41314.00 ns, 2.5216 ns/op
+OverheadWarmup 8: 16384 op, 41344.00 ns, 2.5234 ns/op
+OverheadWarmup 9: 16384 op, 42291.00 ns, 2.5812 ns/op
+OverheadWarmup 10: 16384 op, 41357.00 ns, 2.5242 ns/op
+
+OverheadActual 1: 16384 op, 41535.00 ns, 2.5351 ns/op
+OverheadActual 2: 16384 op, 41715.00 ns, 2.5461 ns/op
+OverheadActual 3: 16384 op, 42861.00 ns, 2.6160 ns/op
+OverheadActual 4: 16384 op, 41502.00 ns, 2.5331 ns/op
+OverheadActual 5: 16384 op, 41549.00 ns, 2.5359 ns/op
+OverheadActual 6: 16384 op, 41379.00 ns, 2.5256 ns/op
+OverheadActual 7: 16384 op, 42391.00 ns, 2.5873 ns/op
+OverheadActual 8: 16384 op, 41464.00 ns, 2.5308 ns/op
+OverheadActual 9: 16384 op, 42734.00 ns, 2.6083 ns/op
+OverheadActual 10: 16384 op, 41432.00 ns, 2.5288 ns/op
+OverheadActual 11: 16384 op, 42227.00 ns, 2.5773 ns/op
+OverheadActual 12: 16384 op, 41480.00 ns, 2.5317 ns/op
+OverheadActual 13: 16384 op, 41405.00 ns, 2.5272 ns/op
+OverheadActual 14: 16384 op, 41561.00 ns, 2.5367 ns/op
+OverheadActual 15: 16384 op, 42211.00 ns, 2.5764 ns/op
+
+WorkloadWarmup 1: 16384 op, 584003034.00 ns, 35.6447 us/op
+WorkloadWarmup 2: 16384 op, 588226151.00 ns, 35.9025 us/op
+WorkloadWarmup 3: 16384 op, 580952779.00 ns, 35.4585 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 605587954.00 ns, 36.9622 us/op
+WorkloadActual 2: 16384 op, 594637728.00 ns, 36.2938 us/op
+WorkloadActual 3: 16384 op, 587387591.00 ns, 35.8513 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 605546405.00 ns, 36.9596 us/op
+WorkloadResult 2: 16384 op, 594596179.00 ns, 36.2913 us/op
+WorkloadResult 3: 16384 op, 587346042.00 ns, 35.8488 us/op
+// GC: 42 0 0 730595328 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 382035 has exited with code 0.
+
+Mean = 36.367 μs, StdErr = 0.323 μs (0.89%), N = 3, StdDev = 0.559 μs
+Min = 35.849 μs, Q1 = 36.070 μs, Median = 36.291 μs, Q3 = 36.625 μs, Max = 36.960 μs
+IQR = 0.555 μs, LowerFence = 35.237 μs, UpperFence = 37.459 μs
+ConfidenceInterval = [26.164 μs; 46.569 μs] (CI 99.9%), Margin = 10.203 μs (28.06% of Mean)
+Skewness = 0.13, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 9 (81.8 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan --job ShortRun --benchmarkId 2 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 250458.00 ns, 250.4580 us/op
+WorkloadJitting 1: 1 op, 3246573.00 ns, 3.2466 ms/op
+
+OverheadJitting 2: 16 op, 532243.00 ns, 33.2652 us/op
+WorkloadJitting 2: 16 op, 1662790.00 ns, 103.9244 us/op
+
+WorkloadPilot 1: 16 op, 1287472.00 ns, 80.4670 us/op
+WorkloadPilot 2: 32 op, 2183789.00 ns, 68.2434 us/op
+WorkloadPilot 3: 64 op, 4416987.00 ns, 69.0154 us/op
+WorkloadPilot 4: 128 op, 8758896.00 ns, 68.4289 us/op
+WorkloadPilot 5: 256 op, 17114343.00 ns, 66.8529 us/op
+WorkloadPilot 6: 512 op, 34236459.00 ns, 66.8681 us/op
+WorkloadPilot 7: 1024 op, 75945695.00 ns, 74.1657 us/op
+WorkloadPilot 8: 2048 op, 73833330.00 ns, 36.0514 us/op
+WorkloadPilot 9: 4096 op, 103647195.00 ns, 25.3045 us/op
+WorkloadPilot 10: 8192 op, 201705580.00 ns, 24.6223 us/op
+WorkloadPilot 11: 16384 op, 403612450.00 ns, 24.6345 us/op
+WorkloadPilot 12: 32768 op, 823699150.00 ns, 25.1373 us/op
+
+OverheadWarmup 1: 32768 op, 90329.00 ns, 2.7566 ns/op
+OverheadWarmup 2: 32768 op, 82597.00 ns, 2.5207 ns/op
+OverheadWarmup 3: 32768 op, 83471.00 ns, 2.5473 ns/op
+OverheadWarmup 4: 32768 op, 82347.00 ns, 2.5130 ns/op
+OverheadWarmup 5: 32768 op, 83319.00 ns, 2.5427 ns/op
+OverheadWarmup 6: 32768 op, 82403.00 ns, 2.5147 ns/op
+
+OverheadActual 1: 32768 op, 83436.00 ns, 2.5463 ns/op
+OverheadActual 2: 32768 op, 82804.00 ns, 2.5270 ns/op
+OverheadActual 3: 32768 op, 84022.00 ns, 2.5641 ns/op
+OverheadActual 4: 32768 op, 82509.00 ns, 2.5180 ns/op
+OverheadActual 5: 32768 op, 83413.00 ns, 2.5456 ns/op
+OverheadActual 6: 32768 op, 82404.00 ns, 2.5148 ns/op
+OverheadActual 7: 32768 op, 83224.00 ns, 2.5398 ns/op
+OverheadActual 8: 32768 op, 82560.00 ns, 2.5195 ns/op
+OverheadActual 9: 32768 op, 83070.00 ns, 2.5351 ns/op
+OverheadActual 10: 32768 op, 82369.00 ns, 2.5137 ns/op
+OverheadActual 11: 32768 op, 87838.00 ns, 2.6806 ns/op
+OverheadActual 12: 32768 op, 82467.00 ns, 2.5167 ns/op
+OverheadActual 13: 32768 op, 82988.00 ns, 2.5326 ns/op
+OverheadActual 14: 32768 op, 90956.00 ns, 2.7758 ns/op
+OverheadActual 15: 32768 op, 88202.00 ns, 2.6917 ns/op
+
+WorkloadWarmup 1: 32768 op, 813648382.00 ns, 24.8306 us/op
+WorkloadWarmup 2: 32768 op, 818396958.00 ns, 24.9755 us/op
+WorkloadWarmup 3: 32768 op, 810596004.00 ns, 24.7374 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 828287759.00 ns, 25.2773 us/op
+WorkloadActual 2: 32768 op, 809517332.00 ns, 24.7045 us/op
+WorkloadActual 3: 32768 op, 806366456.00 ns, 24.6084 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 828204689.00 ns, 25.2748 us/op
+WorkloadResult 2: 32768 op, 809434262.00 ns, 24.7020 us/op
+WorkloadResult 3: 32768 op, 806283386.00 ns, 24.6058 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 382260 has exited with code 0.
+
+Mean = 24.861 μs, StdErr = 0.209 μs (0.84%), N = 3, StdDev = 0.362 μs
+Min = 24.606 μs, Q1 = 24.654 μs, Median = 24.702 μs, Q3 = 24.988 μs, Max = 25.275 μs
+IQR = 0.334 μs, LowerFence = 24.152 μs, UpperFence = 25.490 μs
+ConfidenceInterval = [18.262 μs; 31.459 μs] (CI 99.9%), Margin = 6.599 μs (26.54% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 8 (72.7 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck --job ShortRun --benchmarkId 3 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 233071.00 ns, 233.0710 us/op
+WorkloadJitting 1: 1 op, 2989597.00 ns, 2.9896 ms/op
+
+OverheadJitting 2: 16 op, 490445.00 ns, 30.6528 us/op
+WorkloadJitting 2: 16 op, 1614270.00 ns, 100.8919 us/op
+
+WorkloadPilot 1: 16 op, 1127016.00 ns, 70.4385 us/op
+WorkloadPilot 2: 32 op, 2171704.00 ns, 67.8658 us/op
+WorkloadPilot 3: 64 op, 4437671.00 ns, 69.3386 us/op
+WorkloadPilot 4: 128 op, 8591571.00 ns, 67.1216 us/op
+WorkloadPilot 5: 256 op, 16979899.00 ns, 66.3277 us/op
+WorkloadPilot 6: 512 op, 34869192.00 ns, 68.1039 us/op
+WorkloadPilot 7: 1024 op, 73211931.00 ns, 71.4960 us/op
+WorkloadPilot 8: 2048 op, 80957744.00 ns, 39.5301 us/op
+WorkloadPilot 9: 4096 op, 101686157.00 ns, 24.8257 us/op
+WorkloadPilot 10: 8192 op, 202896307.00 ns, 24.7676 us/op
+WorkloadPilot 11: 16384 op, 403362958.00 ns, 24.6193 us/op
+WorkloadPilot 12: 32768 op, 814738491.00 ns, 24.8638 us/op
+
+OverheadWarmup 1: 32768 op, 104156.00 ns, 3.1786 ns/op
+OverheadWarmup 2: 32768 op, 101388.00 ns, 3.0941 ns/op
+OverheadWarmup 3: 32768 op, 118321.00 ns, 3.6109 ns/op
+OverheadWarmup 4: 32768 op, 120517.00 ns, 3.6779 ns/op
+OverheadWarmup 5: 32768 op, 101920.00 ns, 3.1104 ns/op
+OverheadWarmup 6: 32768 op, 112748.00 ns, 3.4408 ns/op
+OverheadWarmup 7: 32768 op, 113768.00 ns, 3.4719 ns/op
+OverheadWarmup 8: 32768 op, 117970.00 ns, 3.6002 ns/op
+OverheadWarmup 9: 32768 op, 118252.00 ns, 3.6088 ns/op
+OverheadWarmup 10: 32768 op, 109623.00 ns, 3.3454 ns/op
+
+OverheadActual 1: 32768 op, 110344.00 ns, 3.3674 ns/op
+OverheadActual 2: 32768 op, 82135.00 ns, 2.5066 ns/op
+OverheadActual 3: 32768 op, 105149.00 ns, 3.2089 ns/op
+OverheadActual 4: 32768 op, 109060.00 ns, 3.3282 ns/op
+OverheadActual 5: 32768 op, 106869.00 ns, 3.2614 ns/op
+OverheadActual 6: 32768 op, 113743.00 ns, 3.4712 ns/op
+OverheadActual 7: 32768 op, 114578.00 ns, 3.4966 ns/op
+OverheadActual 8: 32768 op, 123586.00 ns, 3.7715 ns/op
+OverheadActual 9: 32768 op, 113819.00 ns, 3.4735 ns/op
+OverheadActual 10: 32768 op, 113345.00 ns, 3.4590 ns/op
+OverheadActual 11: 32768 op, 114300.00 ns, 3.4882 ns/op
+OverheadActual 12: 32768 op, 112976.00 ns, 3.4478 ns/op
+OverheadActual 13: 32768 op, 118245.00 ns, 3.6086 ns/op
+OverheadActual 14: 32768 op, 114155.00 ns, 3.4837 ns/op
+OverheadActual 15: 32768 op, 100749.00 ns, 3.0746 ns/op
+OverheadActual 16: 32768 op, 112887.00 ns, 3.4450 ns/op
+OverheadActual 17: 32768 op, 129232.00 ns, 3.9438 ns/op
+OverheadActual 18: 32768 op, 108800.00 ns, 3.3203 ns/op
+OverheadActual 19: 32768 op, 116839.00 ns, 3.5656 ns/op
+OverheadActual 20: 32768 op, 118769.00 ns, 3.6245 ns/op
+
+WorkloadWarmup 1: 32768 op, 818791575.00 ns, 24.9875 us/op
+WorkloadWarmup 2: 32768 op, 819464104.00 ns, 25.0081 us/op
+WorkloadWarmup 3: 32768 op, 813936545.00 ns, 24.8394 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 821457729.00 ns, 25.0689 us/op
+WorkloadActual 2: 32768 op, 813869180.00 ns, 24.8373 us/op
+WorkloadActual 3: 32768 op, 813794931.00 ns, 24.8351 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 821344185.00 ns, 25.0654 us/op
+WorkloadResult 2: 32768 op, 813755636.00 ns, 24.8339 us/op
+WorkloadResult 3: 32768 op, 813681387.00 ns, 24.8316 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 382447 has exited with code 0.
+
+Mean = 24.910 μs, StdErr = 0.078 μs (0.31%), N = 3, StdDev = 0.134 μs
+Min = 24.832 μs, Q1 = 24.833 μs, Median = 24.834 μs, Q3 = 24.950 μs, Max = 25.065 μs
+IQR = 0.117 μs, LowerFence = 24.657 μs, UpperFence = 25.125 μs
+ConfidenceInterval = [22.459 μs; 27.362 μs] (CI 99.9%), Margin = 2.451 μs (9.84% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 7 (63.6 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck --job ShortRun --benchmarkId 4 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 240339.00 ns, 240.3390 us/op
+WorkloadJitting 1: 1 op, 3037836.00 ns, 3.0378 ms/op
+
+OverheadJitting 2: 16 op, 484160.00 ns, 30.2600 us/op
+WorkloadJitting 2: 16 op, 1662675.00 ns, 103.9172 us/op
+
+WorkloadPilot 1: 16 op, 1176471.00 ns, 73.5294 us/op
+WorkloadPilot 2: 32 op, 2655274.00 ns, 82.9773 us/op
+WorkloadPilot 3: 64 op, 4611641.00 ns, 72.0569 us/op
+WorkloadPilot 4: 128 op, 9317105.00 ns, 72.7899 us/op
+WorkloadPilot 5: 256 op, 17668363.00 ns, 69.0170 us/op
+WorkloadPilot 6: 512 op, 36572948.00 ns, 71.4315 us/op
+WorkloadPilot 7: 1024 op, 94147700.00 ns, 91.9411 us/op
+WorkloadPilot 8: 2048 op, 60574122.00 ns, 29.5772 us/op
+WorkloadPilot 9: 4096 op, 102856905.00 ns, 25.1115 us/op
+WorkloadPilot 10: 8192 op, 201047128.00 ns, 24.5419 us/op
+WorkloadPilot 11: 16384 op, 396597746.00 ns, 24.2064 us/op
+WorkloadPilot 12: 32768 op, 798535509.00 ns, 24.3694 us/op
+
+OverheadWarmup 1: 32768 op, 84278.00 ns, 2.5720 ns/op
+OverheadWarmup 2: 32768 op, 82428.00 ns, 2.5155 ns/op
+OverheadWarmup 3: 32768 op, 82966.00 ns, 2.5319 ns/op
+OverheadWarmup 4: 32768 op, 81846.00 ns, 2.4977 ns/op
+OverheadWarmup 5: 32768 op, 82590.00 ns, 2.5204 ns/op
+OverheadWarmup 6: 32768 op, 81696.00 ns, 2.4932 ns/op
+
+OverheadActual 1: 32768 op, 83550.00 ns, 2.5497 ns/op
+OverheadActual 2: 32768 op, 82028.00 ns, 2.5033 ns/op
+OverheadActual 3: 32768 op, 83445.00 ns, 2.5465 ns/op
+OverheadActual 4: 32768 op, 81828.00 ns, 2.4972 ns/op
+OverheadActual 5: 32768 op, 82888.00 ns, 2.5295 ns/op
+OverheadActual 6: 32768 op, 81860.00 ns, 2.4982 ns/op
+OverheadActual 7: 32768 op, 97289.00 ns, 2.9690 ns/op
+OverheadActual 8: 32768 op, 81613.00 ns, 2.4906 ns/op
+OverheadActual 9: 32768 op, 82725.00 ns, 2.5246 ns/op
+OverheadActual 10: 32768 op, 105278.00 ns, 3.2128 ns/op
+OverheadActual 11: 32768 op, 82543.00 ns, 2.5190 ns/op
+OverheadActual 12: 32768 op, 81765.00 ns, 2.4953 ns/op
+OverheadActual 13: 32768 op, 95736.00 ns, 2.9216 ns/op
+OverheadActual 14: 32768 op, 82000.00 ns, 2.5024 ns/op
+OverheadActual 15: 32768 op, 82420.00 ns, 2.5153 ns/op
+
+WorkloadWarmup 1: 32768 op, 804754951.00 ns, 24.5592 us/op
+WorkloadWarmup 2: 32768 op, 824981785.00 ns, 25.1764 us/op
+WorkloadWarmup 3: 32768 op, 807233733.00 ns, 24.6348 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 813535370.00 ns, 24.8271 us/op
+WorkloadActual 2: 32768 op, 813599069.00 ns, 24.8291 us/op
+WorkloadActual 3: 32768 op, 811145982.00 ns, 24.7542 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 813452827.00 ns, 24.8246 us/op
+WorkloadResult 2: 32768 op, 813516526.00 ns, 24.8266 us/op
+WorkloadResult 3: 32768 op, 811063439.00 ns, 24.7517 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 382737 has exited with code 0.
+
+Mean = 24.801 μs, StdErr = 0.025 μs (0.10%), N = 3, StdDev = 0.043 μs
+Min = 24.752 μs, Q1 = 24.788 μs, Median = 24.825 μs, Q3 = 24.826 μs, Max = 24.827 μs
+IQR = 0.037 μs, LowerFence = 24.732 μs, UpperFence = 24.882 μs
+ConfidenceInterval = [24.022 μs; 25.579 μs] (CI 99.9%), Margin = 0.778 μs (3.14% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 6 (54.5 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripWhitespace_Benchmark --job ShortRun --benchmarkId 5 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 293987.00 ns, 293.9870 us/op
+WorkloadJitting 1: 1 op, 12125098.00 ns, 12.1251 ms/op
+
+OverheadJitting 2: 16 op, 668721.00 ns, 41.7951 us/op
+WorkloadJitting 2: 16 op, 793015.00 ns, 49.5634 us/op
+
+WorkloadPilot 1: 16 op, 41953.00 ns, 2.6221 us/op
+WorkloadPilot 2: 32 op, 63486.00 ns, 1.9839 us/op
+WorkloadPilot 3: 64 op, 124336.00 ns, 1.9428 us/op
+WorkloadPilot 4: 128 op, 213687.00 ns, 1.6694 us/op
+WorkloadPilot 5: 256 op, 419363.00 ns, 1.6381 us/op
+WorkloadPilot 6: 512 op, 798782.00 ns, 1.5601 us/op
+WorkloadPilot 7: 1024 op, 1692410.00 ns, 1.6527 us/op
+WorkloadPilot 8: 2048 op, 3284974.00 ns, 1.6040 us/op
+WorkloadPilot 9: 4096 op, 6438633.00 ns, 1.5719 us/op
+WorkloadPilot 10: 8192 op, 12847528.00 ns, 1.5683 us/op
+WorkloadPilot 11: 16384 op, 25533866.00 ns, 1.5585 us/op
+WorkloadPilot 12: 32768 op, 51196908.00 ns, 1.5624 us/op
+WorkloadPilot 13: 65536 op, 133041623.00 ns, 2.0301 us/op
+WorkloadPilot 14: 131072 op, 114738658.00 ns, 875.3865 ns/op
+WorkloadPilot 15: 262144 op, 183548708.00 ns, 700.1828 ns/op
+WorkloadPilot 16: 524288 op, 352844566.00 ns, 672.9976 ns/op
+WorkloadPilot 17: 1048576 op, 711331552.00 ns, 678.3786 ns/op
+
+OverheadWarmup 1: 1048576 op, 5062945.00 ns, 4.8284 ns/op
+OverheadWarmup 2: 1048576 op, 5221826.00 ns, 4.9799 ns/op
+OverheadWarmup 3: 1048576 op, 5091070.00 ns, 4.8552 ns/op
+OverheadWarmup 4: 1048576 op, 5043759.00 ns, 4.8101 ns/op
+OverheadWarmup 5: 1048576 op, 5441056.00 ns, 5.1890 ns/op
+OverheadWarmup 6: 1048576 op, 5043305.00 ns, 4.8097 ns/op
+
+OverheadActual 1: 1048576 op, 5248179.00 ns, 5.0051 ns/op
+OverheadActual 2: 1048576 op, 5029743.00 ns, 4.7967 ns/op
+OverheadActual 3: 1048576 op, 5299444.00 ns, 5.0539 ns/op
+OverheadActual 4: 1048576 op, 5100686.00 ns, 4.8644 ns/op
+OverheadActual 5: 1048576 op, 5020005.00 ns, 4.7874 ns/op
+OverheadActual 6: 1048576 op, 5025374.00 ns, 4.7926 ns/op
+OverheadActual 7: 1048576 op, 5374039.00 ns, 5.1251 ns/op
+OverheadActual 8: 1048576 op, 5021747.00 ns, 4.7891 ns/op
+OverheadActual 9: 1048576 op, 5013329.00 ns, 4.7811 ns/op
+OverheadActual 10: 1048576 op, 5308229.00 ns, 5.0623 ns/op
+OverheadActual 11: 1048576 op, 5131172.00 ns, 4.8935 ns/op
+OverheadActual 12: 1048576 op, 5014286.00 ns, 4.7820 ns/op
+OverheadActual 13: 1048576 op, 5369268.00 ns, 5.1205 ns/op
+OverheadActual 14: 1048576 op, 5041037.00 ns, 4.8075 ns/op
+OverheadActual 15: 1048576 op, 5075813.00 ns, 4.8407 ns/op
+
+WorkloadWarmup 1: 1048576 op, 715350816.00 ns, 682.2117 ns/op
+WorkloadWarmup 2: 1048576 op, 702621332.00 ns, 670.0719 ns/op
+WorkloadWarmup 3: 1048576 op, 699949306.00 ns, 667.5237 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 701363917.00 ns, 668.8728 ns/op
+WorkloadActual 2: 1048576 op, 699336188.00 ns, 666.9390 ns/op
+WorkloadActual 3: 1048576 op, 701632171.00 ns, 669.1286 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 696288104.00 ns, 664.0321 ns/op
+WorkloadResult 2: 1048576 op, 694260375.00 ns, 662.0983 ns/op
+WorkloadResult 3: 1048576 op, 696556358.00 ns, 664.2879 ns/op
+// GC: 3 0 0 67109280 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 382926 has exited with code 0.
+
+Mean = 663.473 ns, StdErr = 0.691 ns (0.10%), N = 3, StdDev = 1.197 ns
+Min = 662.098 ns, Q1 = 663.065 ns, Median = 664.032 ns, Q3 = 664.160 ns, Max = 664.288 ns
+IQR = 1.095 ns, LowerFence = 661.423 ns, UpperFence = 665.802 ns
+ConfidenceInterval = [641.632 ns; 685.314 ns] (CI 99.9%), Margin = 21.841 ns (3.29% of Mean)
+Skewness = -0.37, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 5 (45.5 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.GetFileExtension_Benchmark --job ShortRun --benchmarkId 6 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 275047.00 ns, 275.0470 us/op
+WorkloadJitting 1: 1 op, 15136536.00 ns, 15.1365 ms/op
+
+OverheadJitting 2: 16 op, 654509.00 ns, 40.9068 us/op
+WorkloadJitting 2: 16 op, 803228.00 ns, 50.2018 us/op
+
+WorkloadPilot 1: 16 op, 37755.00 ns, 2.3597 us/op
+WorkloadPilot 2: 32 op, 55746.00 ns, 1.7421 us/op
+WorkloadPilot 3: 64 op, 83966.00 ns, 1.3120 us/op
+WorkloadPilot 4: 128 op, 157606.00 ns, 1.2313 us/op
+WorkloadPilot 5: 256 op, 310641.00 ns, 1.2134 us/op
+WorkloadPilot 6: 512 op, 581267.00 ns, 1.1353 us/op
+WorkloadPilot 7: 1024 op, 922173.00 ns, 900.5596 ns/op
+WorkloadPilot 8: 2048 op, 1945481.00 ns, 949.9419 ns/op
+WorkloadPilot 9: 4096 op, 3874565.00 ns, 945.9387 ns/op
+WorkloadPilot 10: 8192 op, 7769191.00 ns, 948.3876 ns/op
+WorkloadPilot 11: 16384 op, 15056411.00 ns, 918.9704 ns/op
+WorkloadPilot 12: 32768 op, 30628659.00 ns, 934.7125 ns/op
+WorkloadPilot 13: 65536 op, 47917997.00 ns, 731.1706 ns/op
+WorkloadPilot 14: 131072 op, 175765174.00 ns, 1.3410 us/op
+WorkloadPilot 15: 262144 op, 149595302.00 ns, 570.6608 ns/op
+WorkloadPilot 16: 524288 op, 246943581.00 ns, 471.0075 ns/op
+WorkloadPilot 17: 1048576 op, 492304333.00 ns, 469.4980 ns/op
+WorkloadPilot 18: 2097152 op, 966397478.00 ns, 460.8142 ns/op
+
+OverheadWarmup 1: 2097152 op, 9924561.00 ns, 4.7324 ns/op
+OverheadWarmup 2: 2097152 op, 9927263.00 ns, 4.7337 ns/op
+OverheadWarmup 3: 2097152 op, 9906677.00 ns, 4.7239 ns/op
+OverheadWarmup 4: 2097152 op, 9905574.00 ns, 4.7233 ns/op
+OverheadWarmup 5: 2097152 op, 9917734.00 ns, 4.7291 ns/op
+OverheadWarmup 6: 2097152 op, 9942220.00 ns, 4.7408 ns/op
+OverheadWarmup 7: 2097152 op, 9928170.00 ns, 4.7341 ns/op
+
+OverheadActual 1: 2097152 op, 9903238.00 ns, 4.7222 ns/op
+OverheadActual 2: 2097152 op, 9894517.00 ns, 4.7181 ns/op
+OverheadActual 3: 2097152 op, 9928742.00 ns, 4.7344 ns/op
+OverheadActual 4: 2097152 op, 9923278.00 ns, 4.7318 ns/op
+OverheadActual 5: 2097152 op, 9987781.00 ns, 4.7625 ns/op
+OverheadActual 6: 2097152 op, 9960412.00 ns, 4.7495 ns/op
+OverheadActual 7: 2097152 op, 9901572.00 ns, 4.7214 ns/op
+OverheadActual 8: 2097152 op, 9958122.00 ns, 4.7484 ns/op
+OverheadActual 9: 2097152 op, 9870381.00 ns, 4.7066 ns/op
+OverheadActual 10: 2097152 op, 9913774.00 ns, 4.7273 ns/op
+OverheadActual 11: 2097152 op, 9911170.00 ns, 4.7260 ns/op
+OverheadActual 12: 2097152 op, 9881527.00 ns, 4.7119 ns/op
+OverheadActual 13: 2097152 op, 9843255.00 ns, 4.6936 ns/op
+OverheadActual 14: 2097152 op, 9938862.00 ns, 4.7392 ns/op
+OverheadActual 15: 2097152 op, 9906749.00 ns, 4.7239 ns/op
+
+WorkloadWarmup 1: 2097152 op, 981540895.00 ns, 468.0352 ns/op
+WorkloadWarmup 2: 2097152 op, 990174341.00 ns, 472.1519 ns/op
+WorkloadWarmup 3: 2097152 op, 982837956.00 ns, 468.6537 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 2097152 op, 984533193.00 ns, 469.4620 ns/op
+WorkloadActual 2: 2097152 op, 1000815212.00 ns, 477.2259 ns/op
+WorkloadActual 3: 2097152 op, 1002507708.00 ns, 478.0329 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 2097152 op, 974622023.00 ns, 464.7360 ns/op
+WorkloadResult 2: 2097152 op, 990904042.00 ns, 472.4999 ns/op
+WorkloadResult 3: 2097152 op, 992596538.00 ns, 473.3069 ns/op
+// GC: 67 0 0 1157627904 2097152
+// Threading: 0 0 2097152
+
+// AfterAll
+// Benchmark Process 383178 has exited with code 0.
+
+Mean = 470.181 ns, StdErr = 2.732 ns (0.58%), N = 3, StdDev = 4.733 ns
+Min = 464.736 ns, Q1 = 468.618 ns, Median = 472.500 ns, Q3 = 472.903 ns, Max = 473.307 ns
+IQR = 4.285 ns, LowerFence = 462.190 ns, UpperFence = 479.332 ns
+ConfidenceInterval = [383.839 ns; 556.523 ns] (CI 99.9%), Margin = 86.342 ns (18.36% of Mean)
+Skewness = -0.37, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 4 (36.4 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripHtml_Benchmark --job ShortRun --benchmarkId 7 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 260515.00 ns, 260.5150 us/op
+WorkloadJitting 1: 1 op, 21636192.00 ns, 21.6362 ms/op
+
+OverheadJitting 2: 16 op, 695805.00 ns, 43.4878 us/op
+WorkloadJitting 2: 16 op, 859493.00 ns, 53.7183 us/op
+
+WorkloadPilot 1: 16 op, 40827.00 ns, 2.5517 us/op
+WorkloadPilot 2: 32 op, 58529.00 ns, 1.8290 us/op
+WorkloadPilot 3: 64 op, 95159.00 ns, 1.4869 us/op
+WorkloadPilot 4: 128 op, 193945.00 ns, 1.5152 us/op
+WorkloadPilot 5: 256 op, 635441.00 ns, 2.4822 us/op
+WorkloadPilot 6: 512 op, 721822.00 ns, 1.4098 us/op
+WorkloadPilot 7: 1024 op, 1471119.00 ns, 1.4366 us/op
+WorkloadPilot 8: 2048 op, 3315105.00 ns, 1.6187 us/op
+WorkloadPilot 9: 4096 op, 5998779.00 ns, 1.4645 us/op
+WorkloadPilot 10: 8192 op, 11581158.00 ns, 1.4137 us/op
+WorkloadPilot 11: 16384 op, 23333980.00 ns, 1.4242 us/op
+WorkloadPilot 12: 32768 op, 46528718.00 ns, 1.4199 us/op
+WorkloadPilot 13: 65536 op, 83873023.00 ns, 1.2798 us/op
+WorkloadPilot 14: 131072 op, 100440041.00 ns, 766.2967 ns/op
+WorkloadPilot 15: 262144 op, 200946813.00 ns, 766.5513 ns/op
+WorkloadPilot 16: 524288 op, 397376068.00 ns, 757.9347 ns/op
+WorkloadPilot 17: 1048576 op, 768389615.00 ns, 732.7934 ns/op
+
+OverheadWarmup 1: 1048576 op, 5015367.00 ns, 4.7830 ns/op
+OverheadWarmup 2: 1048576 op, 5004596.00 ns, 4.7728 ns/op
+OverheadWarmup 3: 1048576 op, 5234823.00 ns, 4.9923 ns/op
+OverheadWarmup 4: 1048576 op, 4999863.00 ns, 4.7682 ns/op
+OverheadWarmup 5: 1048576 op, 5045491.00 ns, 4.8118 ns/op
+OverheadWarmup 6: 1048576 op, 5044169.00 ns, 4.8105 ns/op
+
+OverheadActual 1: 1048576 op, 5014404.00 ns, 4.7821 ns/op
+OverheadActual 2: 1048576 op, 5029095.00 ns, 4.7961 ns/op
+OverheadActual 3: 1048576 op, 5021806.00 ns, 4.7892 ns/op
+OverheadActual 4: 1048576 op, 5041406.00 ns, 4.8079 ns/op
+OverheadActual 5: 1048576 op, 5011652.00 ns, 4.7795 ns/op
+OverheadActual 6: 1048576 op, 5005893.00 ns, 4.7740 ns/op
+OverheadActual 7: 1048576 op, 5039270.00 ns, 4.8058 ns/op
+OverheadActual 8: 1048576 op, 5017948.00 ns, 4.7855 ns/op
+OverheadActual 9: 1048576 op, 5023579.00 ns, 4.7909 ns/op
+OverheadActual 10: 1048576 op, 5067016.00 ns, 4.8323 ns/op
+OverheadActual 11: 1048576 op, 5023969.00 ns, 4.7912 ns/op
+OverheadActual 12: 1048576 op, 5030602.00 ns, 4.7976 ns/op
+OverheadActual 13: 1048576 op, 5014002.00 ns, 4.7817 ns/op
+OverheadActual 14: 1048576 op, 5022383.00 ns, 4.7897 ns/op
+OverheadActual 15: 1048576 op, 5015234.00 ns, 4.7829 ns/op
+
+WorkloadWarmup 1: 1048576 op, 773828701.00 ns, 737.9806 ns/op
+WorkloadWarmup 2: 1048576 op, 786647749.00 ns, 750.2058 ns/op
+WorkloadWarmup 3: 1048576 op, 766593269.00 ns, 731.0803 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 773115983.00 ns, 737.3009 ns/op
+WorkloadActual 2: 1048576 op, 781490437.00 ns, 745.2874 ns/op
+WorkloadActual 3: 1048576 op, 767371917.00 ns, 731.8229 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 768093600.00 ns, 732.5111 ns/op
+WorkloadResult 2: 1048576 op, 776468054.00 ns, 740.4976 ns/op
+WorkloadResult 3: 1048576 op, 762349534.00 ns, 727.0332 ns/op
+// GC: 2 0 0 50331960 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 383394 has exited with code 0.
+
+Mean = 733.347 ns, StdErr = 3.909 ns (0.53%), N = 3, StdDev = 6.771 ns
+Min = 727.033 ns, Q1 = 729.772 ns, Median = 732.511 ns, Q3 = 736.504 ns, Max = 740.498 ns
+IQR = 6.732 ns, LowerFence = 719.674 ns, UpperFence = 746.603 ns
+ConfidenceInterval = [609.818 ns; 856.877 ns] (CI 99.9%), Margin = 123.530 ns (16.84% of Mean)
+Skewness = 0.12, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 3 (27.3 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsLowerCase_Benchmark --job ShortRun --benchmarkId 8 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 253019.00 ns, 253.0190 us/op
+WorkloadJitting 1: 1 op, 3608577.00 ns, 3.6086 ms/op
+
+OverheadJitting 2: 16 op, 488452.00 ns, 30.5283 us/op
+WorkloadJitting 2: 16 op, 531832.00 ns, 33.2395 us/op
+
+WorkloadPilot 1: 16 op, 6391.00 ns, 399.4375 ns/op
+WorkloadPilot 2: 32 op, 5955.00 ns, 186.0938 ns/op
+WorkloadPilot 3: 64 op, 5346.00 ns, 83.5313 ns/op
+WorkloadPilot 4: 128 op, 23970.00 ns, 187.2656 ns/op
+WorkloadPilot 5: 256 op, 34882.00 ns, 136.2578 ns/op
+WorkloadPilot 6: 512 op, 36205.00 ns, 70.7129 ns/op
+WorkloadPilot 7: 1024 op, 88499.00 ns, 86.4248 ns/op
+WorkloadPilot 8: 2048 op, 159601.00 ns, 77.9302 ns/op
+WorkloadPilot 9: 4096 op, 299030.00 ns, 73.0054 ns/op
+WorkloadPilot 10: 8192 op, 461597.00 ns, 56.3473 ns/op
+WorkloadPilot 11: 16384 op, 1030762.00 ns, 62.9127 ns/op
+WorkloadPilot 12: 32768 op, 2010960.00 ns, 61.3696 ns/op
+WorkloadPilot 13: 65536 op, 4032333.00 ns, 61.5285 ns/op
+WorkloadPilot 14: 131072 op, 8125224.00 ns, 61.9905 ns/op
+WorkloadPilot 15: 262144 op, 16533594.00 ns, 63.0707 ns/op
+WorkloadPilot 16: 524288 op, 26992479.00 ns, 51.4841 ns/op
+WorkloadPilot 17: 1048576 op, 47019951.00 ns, 44.8417 ns/op
+WorkloadPilot 18: 2097152 op, 65552539.00 ns, 31.2579 ns/op
+WorkloadPilot 19: 4194304 op, 107931260.00 ns, 25.7328 ns/op
+WorkloadPilot 20: 8388608 op, 223704376.00 ns, 26.6676 ns/op
+WorkloadPilot 21: 16777216 op, 437009210.00 ns, 26.0478 ns/op
+WorkloadPilot 22: 33554432 op, 862559070.00 ns, 25.7063 ns/op
+
+OverheadWarmup 1: 33554432 op, 84266521.00 ns, 2.5113 ns/op
+OverheadWarmup 2: 33554432 op, 85085647.00 ns, 2.5357 ns/op
+OverheadWarmup 3: 33554432 op, 83076295.00 ns, 2.4759 ns/op
+OverheadWarmup 4: 33554432 op, 65409354.00 ns, 1.9494 ns/op
+OverheadWarmup 5: 33554432 op, 64853009.00 ns, 1.9328 ns/op
+OverheadWarmup 6: 33554432 op, 64287023.00 ns, 1.9159 ns/op
+OverheadWarmup 7: 33554432 op, 64241377.00 ns, 1.9145 ns/op
+OverheadWarmup 8: 33554432 op, 70469377.00 ns, 2.1002 ns/op
+OverheadWarmup 9: 33554432 op, 65438207.00 ns, 1.9502 ns/op
+
+OverheadActual 1: 33554432 op, 65068186.00 ns, 1.9392 ns/op
+OverheadActual 2: 33554432 op, 66090718.00 ns, 1.9697 ns/op
+OverheadActual 3: 33554432 op, 65681977.00 ns, 1.9575 ns/op
+OverheadActual 4: 33554432 op, 66044977.00 ns, 1.9683 ns/op
+OverheadActual 5: 33554432 op, 64269354.00 ns, 1.9154 ns/op
+OverheadActual 6: 33554432 op, 64257901.00 ns, 1.9150 ns/op
+OverheadActual 7: 33554432 op, 64265359.00 ns, 1.9153 ns/op
+OverheadActual 8: 33554432 op, 64270660.00 ns, 1.9154 ns/op
+OverheadActual 9: 33554432 op, 64357798.00 ns, 1.9180 ns/op
+OverheadActual 10: 33554432 op, 64228656.00 ns, 1.9142 ns/op
+OverheadActual 11: 33554432 op, 64353401.00 ns, 1.9179 ns/op
+OverheadActual 12: 33554432 op, 64244312.00 ns, 1.9146 ns/op
+OverheadActual 13: 33554432 op, 64344060.00 ns, 1.9176 ns/op
+OverheadActual 14: 33554432 op, 64323551.00 ns, 1.9170 ns/op
+OverheadActual 15: 33554432 op, 64577914.00 ns, 1.9246 ns/op
+
+WorkloadWarmup 1: 33554432 op, 861830585.00 ns, 25.6846 ns/op
+WorkloadWarmup 2: 33554432 op, 865276619.00 ns, 25.7873 ns/op
+WorkloadWarmup 3: 33554432 op, 851505689.00 ns, 25.3768 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 33554432 op, 856412613.00 ns, 25.5231 ns/op
+WorkloadActual 2: 33554432 op, 892834370.00 ns, 26.6085 ns/op
+WorkloadActual 3: 33554432 op, 888150996.00 ns, 26.4690 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 33554432 op, 792068553.00 ns, 23.6055 ns/op
+WorkloadResult 2: 33554432 op, 828490310.00 ns, 24.6909 ns/op
+WorkloadResult 3: 33554432 op, 823806936.00 ns, 24.5514 ns/op
+// GC: 93 0 0 1610612736 33554432
+// Threading: 0 0 33554432
+
+// AfterAll
+// Benchmark Process 383679 has exited with code 0.
+
+Mean = 24.283 ns, StdErr = 0.341 ns (1.40%), N = 3, StdDev = 0.591 ns
+Min = 23.605 ns, Q1 = 24.078 ns, Median = 24.551 ns, Q3 = 24.621 ns, Max = 24.691 ns
+IQR = 0.543 ns, LowerFence = 23.264 ns, UpperFence = 25.435 ns
+ConfidenceInterval = [13.509 ns; 35.056 ns] (CI 99.9%), Margin = 10.774 ns (44.37% of Mean)
+Skewness = -0.36, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 2 (18.2 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsUpperCase_Benchmark --job ShortRun --benchmarkId 9 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 238022.00 ns, 238.0220 us/op
+WorkloadJitting 1: 1 op, 3545892.00 ns, 3.5459 ms/op
+
+OverheadJitting 2: 16 op, 495238.00 ns, 30.9524 us/op
+WorkloadJitting 2: 16 op, 510985.00 ns, 31.9366 us/op
+
+WorkloadPilot 1: 16 op, 6037.00 ns, 377.3125 ns/op
+WorkloadPilot 2: 32 op, 5263.00 ns, 164.4688 ns/op
+WorkloadPilot 3: 64 op, 5863.00 ns, 91.6094 ns/op
+WorkloadPilot 4: 128 op, 19974.00 ns, 156.0469 ns/op
+WorkloadPilot 5: 256 op, 59685.00 ns, 233.1445 ns/op
+WorkloadPilot 6: 512 op, 38611.00 ns, 75.4121 ns/op
+WorkloadPilot 7: 1024 op, 84070.00 ns, 82.0996 ns/op
+WorkloadPilot 8: 2048 op, 167761.00 ns, 81.9146 ns/op
+WorkloadPilot 9: 4096 op, 301738.00 ns, 73.6665 ns/op
+WorkloadPilot 10: 8192 op, 488525.00 ns, 59.6344 ns/op
+WorkloadPilot 11: 16384 op, 1042415.00 ns, 63.6240 ns/op
+WorkloadPilot 12: 32768 op, 2057848.00 ns, 62.8005 ns/op
+WorkloadPilot 13: 65536 op, 4093892.00 ns, 62.4678 ns/op
+WorkloadPilot 14: 131072 op, 8499864.00 ns, 64.8488 ns/op
+WorkloadPilot 15: 262144 op, 16700783.00 ns, 63.7084 ns/op
+WorkloadPilot 16: 524288 op, 27257206.00 ns, 51.9890 ns/op
+WorkloadPilot 17: 1048576 op, 47582977.00 ns, 45.3787 ns/op
+WorkloadPilot 18: 2097152 op, 65997364.00 ns, 31.4700 ns/op
+WorkloadPilot 19: 4194304 op, 106833080.00 ns, 25.4710 ns/op
+WorkloadPilot 20: 8388608 op, 214629028.00 ns, 25.5858 ns/op
+WorkloadPilot 21: 16777216 op, 431267037.00 ns, 25.7055 ns/op
+WorkloadPilot 22: 33554432 op, 868030978.00 ns, 25.8693 ns/op
+
+OverheadWarmup 1: 33554432 op, 86202763.00 ns, 2.5690 ns/op
+OverheadWarmup 2: 33554432 op, 86168731.00 ns, 2.5680 ns/op
+OverheadWarmup 3: 33554432 op, 72247834.00 ns, 2.1532 ns/op
+OverheadWarmup 4: 33554432 op, 65197756.00 ns, 1.9430 ns/op
+OverheadWarmup 5: 33554432 op, 65908649.00 ns, 1.9642 ns/op
+OverheadWarmup 6: 33554432 op, 65083983.00 ns, 1.9397 ns/op
+OverheadWarmup 7: 33554432 op, 65440544.00 ns, 1.9503 ns/op
+OverheadWarmup 8: 33554432 op, 65581786.00 ns, 1.9545 ns/op
+OverheadWarmup 9: 33554432 op, 65005691.00 ns, 1.9373 ns/op
+
+OverheadActual 1: 33554432 op, 69136307.00 ns, 2.0604 ns/op
+OverheadActual 2: 33554432 op, 65156246.00 ns, 1.9418 ns/op
+OverheadActual 3: 33554432 op, 65947865.00 ns, 1.9654 ns/op
+OverheadActual 4: 33554432 op, 66664077.00 ns, 1.9867 ns/op
+OverheadActual 5: 33554432 op, 65611345.00 ns, 1.9554 ns/op
+OverheadActual 6: 33554432 op, 65974485.00 ns, 1.9662 ns/op
+OverheadActual 7: 33554432 op, 65870741.00 ns, 1.9631 ns/op
+OverheadActual 8: 33554432 op, 65137079.00 ns, 1.9412 ns/op
+OverheadActual 9: 33554432 op, 65278161.00 ns, 1.9454 ns/op
+OverheadActual 10: 33554432 op, 65096058.00 ns, 1.9400 ns/op
+OverheadActual 11: 33554432 op, 65492255.00 ns, 1.9518 ns/op
+OverheadActual 12: 33554432 op, 65422856.00 ns, 1.9498 ns/op
+OverheadActual 13: 33554432 op, 65325045.00 ns, 1.9468 ns/op
+OverheadActual 14: 33554432 op, 65135325.00 ns, 1.9412 ns/op
+OverheadActual 15: 33554432 op, 65351739.00 ns, 1.9476 ns/op
+
+WorkloadWarmup 1: 33554432 op, 878366284.00 ns, 26.1774 ns/op
+WorkloadWarmup 2: 33554432 op, 869287865.00 ns, 25.9068 ns/op
+WorkloadWarmup 3: 33554432 op, 866813292.00 ns, 25.8330 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 33554432 op, 853187042.00 ns, 25.4270 ns/op
+WorkloadActual 2: 33554432 op, 897272831.00 ns, 26.7408 ns/op
+WorkloadActual 3: 33554432 op, 888812510.00 ns, 26.4887 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 33554432 op, 787764186.00 ns, 23.4772 ns/op
+WorkloadResult 2: 33554432 op, 831849975.00 ns, 24.7911 ns/op
+WorkloadResult 3: 33554432 op, 823389654.00 ns, 24.5389 ns/op
+// GC: 93 0 0 1610612736 33554432
+// Threading: 0 0 33554432
+
+// AfterAll
+// Benchmark Process 383967 has exited with code 0.
+
+Mean = 24.269 ns, StdErr = 0.403 ns (1.66%), N = 3, StdDev = 0.697 ns
+Min = 23.477 ns, Q1 = 24.008 ns, Median = 24.539 ns, Q3 = 24.665 ns, Max = 24.791 ns
+IQR = 0.657 ns, LowerFence = 23.023 ns, UpperFence = 25.650 ns
+ConfidenceInterval = [11.548 ns; 36.990 ns] (CI 99.9%), Margin = 12.721 ns (52.42% of Mean)
+Skewness = -0.33, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 1 (9.1 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark --job ShortRun --benchmarkId 10 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 265912.00 ns, 265.9120 us/op
+WorkloadJitting 1: 1 op, 4621386.00 ns, 4.6214 ms/op
+
+OverheadJitting 2: 16 op, 695516.00 ns, 43.4698 us/op
+WorkloadJitting 2: 16 op, 763436.00 ns, 47.7148 us/op
+
+WorkloadPilot 1: 16 op, 70395.00 ns, 4.3997 us/op
+WorkloadPilot 2: 32 op, 134489.00 ns, 4.2028 us/op
+WorkloadPilot 3: 64 op, 216903.00 ns, 3.3891 us/op
+WorkloadPilot 4: 128 op, 394182.00 ns, 3.0795 us/op
+WorkloadPilot 5: 256 op, 676999.00 ns, 2.6445 us/op
+WorkloadPilot 6: 512 op, 1544882.00 ns, 3.0173 us/op
+WorkloadPilot 7: 1024 op, 3082573.00 ns, 3.0103 us/op
+WorkloadPilot 8: 2048 op, 6005321.00 ns, 2.9323 us/op
+WorkloadPilot 9: 4096 op, 11824173.00 ns, 2.8868 us/op
+WorkloadPilot 10: 8192 op, 23574295.00 ns, 2.8777 us/op
+WorkloadPilot 11: 16384 op, 44403592.00 ns, 2.7102 us/op
+WorkloadPilot 12: 32768 op, 62749307.00 ns, 1.9150 us/op
+WorkloadPilot 13: 65536 op, 40387109.00 ns, 616.2584 ns/op
+WorkloadPilot 14: 131072 op, 77186095.00 ns, 588.8832 ns/op
+WorkloadPilot 15: 262144 op, 151405177.00 ns, 577.5649 ns/op
+WorkloadPilot 16: 524288 op, 307871719.00 ns, 587.2187 ns/op
+WorkloadPilot 17: 1048576 op, 635900662.00 ns, 606.4421 ns/op
+
+OverheadWarmup 1: 1048576 op, 4654490.00 ns, 4.4389 ns/op
+OverheadWarmup 2: 1048576 op, 4670251.00 ns, 4.4539 ns/op
+OverheadWarmup 3: 1048576 op, 4632150.00 ns, 4.4176 ns/op
+OverheadWarmup 4: 1048576 op, 4641648.00 ns, 4.4266 ns/op
+OverheadWarmup 5: 1048576 op, 4679829.00 ns, 4.4630 ns/op
+OverheadWarmup 6: 1048576 op, 4631836.00 ns, 4.4173 ns/op
+
+OverheadActual 1: 1048576 op, 4638598.00 ns, 4.4237 ns/op
+OverheadActual 2: 1048576 op, 4646413.00 ns, 4.4312 ns/op
+OverheadActual 3: 1048576 op, 4627460.00 ns, 4.4131 ns/op
+OverheadActual 4: 1048576 op, 4636416.00 ns, 4.4216 ns/op
+OverheadActual 5: 1048576 op, 4669200.00 ns, 4.4529 ns/op
+OverheadActual 6: 1048576 op, 4648089.00 ns, 4.4328 ns/op
+OverheadActual 7: 1048576 op, 4634900.00 ns, 4.4202 ns/op
+OverheadActual 8: 1048576 op, 4656284.00 ns, 4.4406 ns/op
+OverheadActual 9: 1048576 op, 4644103.00 ns, 4.4290 ns/op
+OverheadActual 10: 1048576 op, 4640661.00 ns, 4.4257 ns/op
+OverheadActual 11: 1048576 op, 4631005.00 ns, 4.4165 ns/op
+OverheadActual 12: 1048576 op, 4650786.00 ns, 4.4353 ns/op
+OverheadActual 13: 1048576 op, 4635315.00 ns, 4.4206 ns/op
+OverheadActual 14: 1048576 op, 4645573.00 ns, 4.4304 ns/op
+OverheadActual 15: 1048576 op, 4642033.00 ns, 4.4270 ns/op
+
+WorkloadWarmup 1: 1048576 op, 623034957.00 ns, 594.1724 ns/op
+WorkloadWarmup 2: 1048576 op, 601140312.00 ns, 573.2921 ns/op
+WorkloadWarmup 3: 1048576 op, 628103602.00 ns, 599.0063 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 624189329.00 ns, 595.2733 ns/op
+WorkloadActual 2: 1048576 op, 635303689.00 ns, 605.8728 ns/op
+WorkloadActual 3: 1048576 op, 637318469.00 ns, 607.7943 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 619547296.00 ns, 590.8463 ns/op
+WorkloadResult 2: 1048576 op, 630661656.00 ns, 601.4458 ns/op
+WorkloadResult 3: 1048576 op, 632676436.00 ns, 603.3673 ns/op
+// GC: 79 0 0 1367343104 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 384264 has exited with code 0.
+
+Mean = 598.553 ns, StdErr = 3.893 ns (0.65%), N = 3, StdDev = 6.743 ns
+Min = 590.846 ns, Q1 = 596.146 ns, Median = 601.446 ns, Q3 = 602.407 ns, Max = 603.367 ns
+IQR = 6.260 ns, LowerFence = 586.755 ns, UpperFence = 611.797 ns
+ConfidenceInterval = [475.534 ns; 721.572 ns] (CI 99.9%), Margin = 123.019 ns (20.55% of Mean)
+Skewness = -0.35, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-07 21:39 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html
+
+// * Detailed results *
+StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 50.119 μs, StdErr = 0.219 μs (0.44%), N = 3, StdDev = 0.379 μs
+Min = 49.702 μs, Q1 = 49.959 μs, Median = 50.215 μs, Q3 = 50.328 μs, Max = 50.441 μs
+IQR = 0.369 μs, LowerFence = 49.405 μs, UpperFence = 50.882 μs
+ConfidenceInterval = [43.212 μs; 57.027 μs] (CI 99.9%), Margin = 6.907 μs (13.78% of Mean)
+Skewness = -0.24, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[49.357 μs ; 50.785 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 36.367 μs, StdErr = 0.323 μs (0.89%), N = 3, StdDev = 0.559 μs
+Min = 35.849 μs, Q1 = 36.070 μs, Median = 36.291 μs, Q3 = 36.625 μs, Max = 36.960 μs
+IQR = 0.555 μs, LowerFence = 35.237 μs, UpperFence = 37.459 μs
+ConfidenceInterval = [26.164 μs; 46.569 μs] (CI 99.9%), Margin = 10.203 μs (28.06% of Mean)
+Skewness = 0.13, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[35.561 μs ; 36.579 μs) | @@
+[36.579 μs ; 37.469 μs) | @
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.861 μs, StdErr = 0.209 μs (0.84%), N = 3, StdDev = 0.362 μs
+Min = 24.606 μs, Q1 = 24.654 μs, Median = 24.702 μs, Q3 = 24.988 μs, Max = 25.275 μs
+IQR = 0.334 μs, LowerFence = 24.152 μs, UpperFence = 25.490 μs
+ConfidenceInterval = [18.262 μs; 31.459 μs] (CI 99.9%), Margin = 6.599 μs (26.54% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[24.277 μs ; 24.983 μs) | @@
+[24.983 μs ; 25.604 μs) | @
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.910 μs, StdErr = 0.078 μs (0.31%), N = 3, StdDev = 0.134 μs
+Min = 24.832 μs, Q1 = 24.833 μs, Median = 24.834 μs, Q3 = 24.950 μs, Max = 25.065 μs
+IQR = 0.117 μs, LowerFence = 24.657 μs, UpperFence = 25.125 μs
+ConfidenceInterval = [22.459 μs; 27.362 μs] (CI 99.9%), Margin = 2.451 μs (9.84% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[24.826 μs ; 25.071 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.801 μs, StdErr = 0.025 μs (0.10%), N = 3, StdDev = 0.043 μs
+Min = 24.752 μs, Q1 = 24.788 μs, Median = 24.825 μs, Q3 = 24.826 μs, Max = 24.827 μs
+IQR = 0.037 μs, LowerFence = 24.732 μs, UpperFence = 24.882 μs
+ConfidenceInterval = [24.022 μs; 25.579 μs] (CI 99.9%), Margin = 0.778 μs (3.14% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[24.750 μs ; 24.828 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 663.473 ns, StdErr = 0.691 ns (0.10%), N = 3, StdDev = 1.197 ns
+Min = 662.098 ns, Q1 = 663.065 ns, Median = 664.032 ns, Q3 = 664.160 ns, Max = 664.288 ns
+IQR = 1.095 ns, LowerFence = 661.423 ns, UpperFence = 665.802 ns
+ConfidenceInterval = [641.632 ns; 685.314 ns] (CI 99.9%), Margin = 21.841 ns (3.29% of Mean)
+Skewness = -0.37, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[661.009 ns ; 665.378 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 470.181 ns, StdErr = 2.732 ns (0.58%), N = 3, StdDev = 4.733 ns
+Min = 464.736 ns, Q1 = 468.618 ns, Median = 472.500 ns, Q3 = 472.903 ns, Max = 473.307 ns
+IQR = 4.285 ns, LowerFence = 462.190 ns, UpperFence = 479.332 ns
+ConfidenceInterval = [383.839 ns; 556.523 ns] (CI 99.9%), Margin = 86.342 ns (18.36% of Mean)
+Skewness = -0.37, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[464.715 ns ; 473.328 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 733.347 ns, StdErr = 3.909 ns (0.53%), N = 3, StdDev = 6.771 ns
+Min = 727.033 ns, Q1 = 729.772 ns, Median = 732.511 ns, Q3 = 736.504 ns, Max = 740.498 ns
+IQR = 6.732 ns, LowerFence = 719.674 ns, UpperFence = 746.603 ns
+ConfidenceInterval = [609.818 ns; 856.877 ns] (CI 99.9%), Margin = 123.530 ns (16.84% of Mean)
+Skewness = 0.12, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[722.474 ns ; 746.660 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.283 ns, StdErr = 0.341 ns (1.40%), N = 3, StdDev = 0.591 ns
+Min = 23.605 ns, Q1 = 24.078 ns, Median = 24.551 ns, Q3 = 24.621 ns, Max = 24.691 ns
+IQR = 0.543 ns, LowerFence = 23.264 ns, UpperFence = 25.435 ns
+ConfidenceInterval = [13.509 ns; 35.056 ns] (CI 99.9%), Margin = 10.774 ns (44.37% of Mean)
+Skewness = -0.36, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[23.068 ns ; 24.084 ns) | @
+[24.084 ns ; 25.228 ns) | @@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.269 ns, StdErr = 0.403 ns (1.66%), N = 3, StdDev = 0.697 ns
+Min = 23.477 ns, Q1 = 24.008 ns, Median = 24.539 ns, Q3 = 24.665 ns, Max = 24.791 ns
+IQR = 0.657 ns, LowerFence = 23.023 ns, UpperFence = 25.650 ns
+ConfidenceInterval = [11.548 ns; 36.990 ns] (CI 99.9%), Margin = 12.721 ns (52.42% of Mean)
+Skewness = -0.33, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[22.843 ns ; 24.030 ns) | @
+[24.030 ns ; 25.426 ns) | @@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 598.553 ns, StdErr = 3.893 ns (0.65%), N = 3, StdDev = 6.743 ns
+Min = 590.846 ns, Q1 = 596.146 ns, Median = 601.446 ns, Q3 = 602.407 ns, Max = 603.367 ns
+IQR = 6.260 ns, LowerFence = 586.755 ns, UpperFence = 611.797 ns
+ConfidenceInterval = [475.534 ns; 721.572 ns] (CI 99.9%), Margin = 123.019 ns (20.55% of Mean)
+Skewness = -0.35, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[584.710 ns ; 609.504 ns) | @@@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100-rc.2.25502.107
+ [Host] : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+
+Job=ShortRun IterationCount=3 LaunchCount=1
+WarmupCount=3
+
+| Method | Mean | Error | StdDev | Gen0 | Allocated |
+|------------------------------------------------------ |-------------:|-------------:|-----------:|-------:|----------:|
+| Linq | 50,119.32 ns | 6,907.26 ns | 378.610 ns | 3.4180 | 59712 B |
+| SplitToHeapStrings | 36,366.55 ns | 10,202.69 ns | 559.244 ns | 2.5635 | 44592 B |
+| SplitToStackSpansWithoutEmptyCheckReversingListAsSpan | 24,860.86 ns | 6,598.58 ns | 361.690 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithoutEmptyCheck | 24,910.29 ns | 2,451.30 ns | 134.364 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithEmptyCheck | 24,800.95 ns | 778.49 ns | 42.672 ns | 0.9766 | 17128 B |
+| StripWhitespace_Benchmark | 663.47 ns | 21.84 ns | 1.197 ns | 0.0029 | 64 B |
+| GetFileExtension_Benchmark | 470.18 ns | 86.34 ns | 4.733 ns | 0.0319 | 552 B |
+| StripHtml_Benchmark | 733.35 ns | 123.53 ns | 6.771 ns | 0.0019 | 48 B |
+| IsLowerCase_Benchmark | 24.28 ns | 10.77 ns | 0.591 ns | 0.0028 | 48 B |
+| IsUpperCase_Benchmark | 24.27 ns | 12.72 ns | 0.697 ns | 0.0028 | 48 B |
+| ReplaceNonAlphanumericChars_String_Benchmark | 598.55 ns | 123.02 ns | 6.743 ns | 0.0753 | 1304 B |
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:01:26 (86.69 sec), executed benchmarks: 11
+
+Global total time: 00:03:08 (188.08 sec), executed benchmarks: 11
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-214012.log b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-214012.log
new file mode 100644
index 0000000000..3efceb625a
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-214012.log
@@ -0,0 +1,1172 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 11 benchmark(s) in total *****
+// ***** Building 1 exe(s) in Parallel: Start *****
+// start dotnet restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 3.99 sec and exited with 0
+// start dotnet build -c Release --no-restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" --output "/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 98.09 sec and exited with 0
+// ***** Done, took 00:01:42 (102.37 sec) *****
+// Found 11 benchmarks:
+// StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+// **************************
+// Benchmark: StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.Linq --job ShortRun --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 237277.00 ns, 237.2770 us/op
+WorkloadJitting 1: 1 op, 10029551.00 ns, 10.0296 ms/op
+
+OverheadJitting 2: 16 op, 558135.00 ns, 34.8834 us/op
+WorkloadJitting 2: 16 op, 3810312.00 ns, 238.1445 us/op
+
+WorkloadPilot 1: 16 op, 2904801.00 ns, 181.5501 us/op
+WorkloadPilot 2: 32 op, 5404847.00 ns, 168.9015 us/op
+WorkloadPilot 3: 64 op, 11492673.00 ns, 179.5730 us/op
+WorkloadPilot 4: 128 op, 22980130.00 ns, 179.5323 us/op
+WorkloadPilot 5: 256 op, 45549713.00 ns, 177.9286 us/op
+WorkloadPilot 6: 512 op, 98427449.00 ns, 192.2411 us/op
+WorkloadPilot 7: 1024 op, 51679098.00 ns, 50.4679 us/op
+WorkloadPilot 8: 2048 op, 101620622.00 ns, 49.6194 us/op
+WorkloadPilot 9: 4096 op, 202216520.00 ns, 49.3693 us/op
+WorkloadPilot 10: 8192 op, 420035274.00 ns, 51.2738 us/op
+WorkloadPilot 11: 16384 op, 821722734.00 ns, 50.1540 us/op
+
+OverheadWarmup 1: 16384 op, 44310.00 ns, 2.7045 ns/op
+OverheadWarmup 2: 16384 op, 41742.00 ns, 2.5477 ns/op
+OverheadWarmup 3: 16384 op, 41538.00 ns, 2.5353 ns/op
+OverheadWarmup 4: 16384 op, 41523.00 ns, 2.5344 ns/op
+OverheadWarmup 5: 16384 op, 42469.00 ns, 2.5921 ns/op
+OverheadWarmup 6: 16384 op, 41560.00 ns, 2.5366 ns/op
+OverheadWarmup 7: 16384 op, 41490.00 ns, 2.5323 ns/op
+OverheadWarmup 8: 16384 op, 45472.00 ns, 2.7754 ns/op
+OverheadWarmup 9: 16384 op, 56309.00 ns, 3.4368 ns/op
+OverheadWarmup 10: 16384 op, 41422.00 ns, 2.5282 ns/op
+
+OverheadActual 1: 16384 op, 71671.00 ns, 4.3745 ns/op
+OverheadActual 2: 16384 op, 59088.00 ns, 3.6064 ns/op
+OverheadActual 3: 16384 op, 60066.00 ns, 3.6661 ns/op
+OverheadActual 4: 16384 op, 60033.00 ns, 3.6641 ns/op
+OverheadActual 5: 16384 op, 59700.00 ns, 3.6438 ns/op
+OverheadActual 6: 16384 op, 61531.00 ns, 3.7556 ns/op
+OverheadActual 7: 16384 op, 63846.00 ns, 3.8969 ns/op
+OverheadActual 8: 16384 op, 62333.00 ns, 3.8045 ns/op
+OverheadActual 9: 16384 op, 62356.00 ns, 3.8059 ns/op
+OverheadActual 10: 16384 op, 59253.00 ns, 3.6165 ns/op
+OverheadActual 11: 16384 op, 60373.00 ns, 3.6849 ns/op
+OverheadActual 12: 16384 op, 60824.00 ns, 3.7124 ns/op
+OverheadActual 13: 16384 op, 78780.00 ns, 4.8083 ns/op
+OverheadActual 14: 16384 op, 58407.00 ns, 3.5649 ns/op
+OverheadActual 15: 16384 op, 60748.00 ns, 3.7078 ns/op
+
+WorkloadWarmup 1: 16384 op, 830076392.00 ns, 50.6638 us/op
+WorkloadWarmup 2: 16384 op, 826444999.00 ns, 50.4422 us/op
+WorkloadWarmup 3: 16384 op, 826824768.00 ns, 50.4654 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 827565757.00 ns, 50.5106 us/op
+WorkloadActual 2: 16384 op, 830369625.00 ns, 50.6817 us/op
+WorkloadActual 3: 16384 op, 832480908.00 ns, 50.8106 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 827505009.00 ns, 50.5069 us/op
+WorkloadResult 2: 16384 op, 830308877.00 ns, 50.6780 us/op
+WorkloadResult 3: 16384 op, 832420160.00 ns, 50.8069 us/op
+// GC: 56 0 0 978321408 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 391407 has exited with code 0.
+
+Mean = 50.664 μs, StdErr = 0.087 μs (0.17%), N = 3, StdDev = 0.150 μs
+Min = 50.507 μs, Q1 = 50.592 μs, Median = 50.678 μs, Q3 = 50.742 μs, Max = 50.807 μs
+IQR = 0.150 μs, LowerFence = 50.367 μs, UpperFence = 50.967 μs
+ConfidenceInterval = [47.918 μs; 53.410 μs] (CI 99.9%), Margin = 2.746 μs (5.42% of Mean)
+Skewness = -0.09, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 10 (90.9 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToHeapStrings --job ShortRun --benchmarkId 1 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 244523.00 ns, 244.5230 us/op
+WorkloadJitting 1: 1 op, 2423206.00 ns, 2.4232 ms/op
+
+OverheadJitting 2: 16 op, 495403.00 ns, 30.9627 us/op
+WorkloadJitting 2: 16 op, 1842006.00 ns, 115.1254 us/op
+
+WorkloadPilot 1: 16 op, 1374824.00 ns, 85.9265 us/op
+WorkloadPilot 2: 32 op, 2479109.00 ns, 77.4722 us/op
+WorkloadPilot 3: 64 op, 5246165.00 ns, 81.9713 us/op
+WorkloadPilot 4: 128 op, 10250289.00 ns, 80.0804 us/op
+WorkloadPilot 5: 256 op, 19895555.00 ns, 77.7170 us/op
+WorkloadPilot 6: 512 op, 35981283.00 ns, 70.2759 us/op
+WorkloadPilot 7: 1024 op, 75926660.00 ns, 74.1471 us/op
+WorkloadPilot 8: 2048 op, 86146938.00 ns, 42.0639 us/op
+WorkloadPilot 9: 4096 op, 147099961.00 ns, 35.9131 us/op
+WorkloadPilot 10: 8192 op, 297750809.00 ns, 36.3465 us/op
+WorkloadPilot 11: 16384 op, 593579171.00 ns, 36.2292 us/op
+
+OverheadWarmup 1: 16384 op, 44535.00 ns, 2.7182 ns/op
+OverheadWarmup 2: 16384 op, 41466.00 ns, 2.5309 ns/op
+OverheadWarmup 3: 16384 op, 41366.00 ns, 2.5248 ns/op
+OverheadWarmup 4: 16384 op, 41472.00 ns, 2.5313 ns/op
+OverheadWarmup 5: 16384 op, 42387.00 ns, 2.5871 ns/op
+OverheadWarmup 6: 16384 op, 41380.00 ns, 2.5256 ns/op
+OverheadWarmup 7: 16384 op, 41358.00 ns, 2.5243 ns/op
+OverheadWarmup 8: 16384 op, 55643.00 ns, 3.3962 ns/op
+OverheadWarmup 9: 16384 op, 42091.00 ns, 2.5690 ns/op
+
+OverheadActual 1: 16384 op, 41678.00 ns, 2.5438 ns/op
+OverheadActual 2: 16384 op, 41697.00 ns, 2.5450 ns/op
+OverheadActual 3: 16384 op, 41589.00 ns, 2.5384 ns/op
+OverheadActual 4: 16384 op, 42584.00 ns, 2.5991 ns/op
+OverheadActual 5: 16384 op, 46804.00 ns, 2.8567 ns/op
+OverheadActual 6: 16384 op, 41429.00 ns, 2.5286 ns/op
+OverheadActual 7: 16384 op, 41425.00 ns, 2.5284 ns/op
+OverheadActual 8: 16384 op, 42063.00 ns, 2.5673 ns/op
+OverheadActual 9: 16384 op, 41423.00 ns, 2.5283 ns/op
+OverheadActual 10: 16384 op, 41309.00 ns, 2.5213 ns/op
+OverheadActual 11: 16384 op, 41455.00 ns, 2.5302 ns/op
+OverheadActual 12: 16384 op, 42007.00 ns, 2.5639 ns/op
+OverheadActual 13: 16384 op, 46505.00 ns, 2.8384 ns/op
+OverheadActual 14: 16384 op, 41563.00 ns, 2.5368 ns/op
+OverheadActual 15: 16384 op, 41471.00 ns, 2.5312 ns/op
+
+WorkloadWarmup 1: 16384 op, 612362625.00 ns, 37.3756 us/op
+WorkloadWarmup 2: 16384 op, 609969702.00 ns, 37.2296 us/op
+WorkloadWarmup 3: 16384 op, 595514200.00 ns, 36.3473 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 588759431.00 ns, 35.9350 us/op
+WorkloadActual 2: 16384 op, 602254348.00 ns, 36.7587 us/op
+WorkloadActual 3: 16384 op, 602548933.00 ns, 36.7767 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 588717842.00 ns, 35.9325 us/op
+WorkloadResult 2: 16384 op, 602212759.00 ns, 36.7561 us/op
+WorkloadResult 3: 16384 op, 602507344.00 ns, 36.7741 us/op
+// GC: 42 0 0 730595328 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 391604 has exited with code 0.
+
+Mean = 36.488 μs, StdErr = 0.278 μs (0.76%), N = 3, StdDev = 0.481 μs
+Min = 35.932 μs, Q1 = 36.344 μs, Median = 36.756 μs, Q3 = 36.765 μs, Max = 36.774 μs
+IQR = 0.421 μs, LowerFence = 35.713 μs, UpperFence = 37.396 μs
+ConfidenceInterval = [27.716 μs; 45.259 μs] (CI 99.9%), Margin = 8.772 μs (24.04% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 9 (81.8 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan --job ShortRun --benchmarkId 2 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 254340.00 ns, 254.3400 us/op
+WorkloadJitting 1: 1 op, 3225705.00 ns, 3.2257 ms/op
+
+OverheadJitting 2: 16 op, 500204.00 ns, 31.2628 us/op
+WorkloadJitting 2: 16 op, 1626283.00 ns, 101.6427 us/op
+
+WorkloadPilot 1: 16 op, 2126200.00 ns, 132.8875 us/op
+WorkloadPilot 2: 32 op, 4185011.00 ns, 130.7816 us/op
+WorkloadPilot 3: 64 op, 7928745.00 ns, 123.8866 us/op
+WorkloadPilot 4: 128 op, 9692445.00 ns, 75.7222 us/op
+WorkloadPilot 5: 256 op, 24659251.00 ns, 96.3252 us/op
+WorkloadPilot 6: 512 op, 35440334.00 ns, 69.2194 us/op
+WorkloadPilot 7: 1024 op, 89143082.00 ns, 87.0538 us/op
+WorkloadPilot 8: 2048 op, 52104393.00 ns, 25.4416 us/op
+WorkloadPilot 9: 4096 op, 103606684.00 ns, 25.2946 us/op
+WorkloadPilot 10: 8192 op, 205943826.00 ns, 25.1396 us/op
+WorkloadPilot 11: 16384 op, 418067515.00 ns, 25.5168 us/op
+WorkloadPilot 12: 32768 op, 828906186.00 ns, 25.2962 us/op
+
+OverheadWarmup 1: 32768 op, 128888.00 ns, 3.9333 ns/op
+OverheadWarmup 2: 32768 op, 82465.00 ns, 2.5166 ns/op
+OverheadWarmup 3: 32768 op, 83637.00 ns, 2.5524 ns/op
+OverheadWarmup 4: 32768 op, 82436.00 ns, 2.5157 ns/op
+OverheadWarmup 5: 32768 op, 83259.00 ns, 2.5409 ns/op
+OverheadWarmup 6: 32768 op, 95496.00 ns, 2.9143 ns/op
+OverheadWarmup 7: 32768 op, 83298.00 ns, 2.5421 ns/op
+
+OverheadActual 1: 32768 op, 98968.00 ns, 3.0203 ns/op
+OverheadActual 2: 32768 op, 100603.00 ns, 3.0702 ns/op
+OverheadActual 3: 32768 op, 98279.00 ns, 2.9992 ns/op
+OverheadActual 4: 32768 op, 83535.00 ns, 2.5493 ns/op
+OverheadActual 5: 32768 op, 82554.00 ns, 2.5193 ns/op
+OverheadActual 6: 32768 op, 95168.00 ns, 2.9043 ns/op
+OverheadActual 7: 32768 op, 82537.00 ns, 2.5188 ns/op
+OverheadActual 8: 32768 op, 83393.00 ns, 2.5450 ns/op
+OverheadActual 9: 32768 op, 82599.00 ns, 2.5207 ns/op
+OverheadActual 10: 32768 op, 83499.00 ns, 2.5482 ns/op
+OverheadActual 11: 32768 op, 82479.00 ns, 2.5171 ns/op
+OverheadActual 12: 32768 op, 95263.00 ns, 2.9072 ns/op
+OverheadActual 13: 32768 op, 82463.00 ns, 2.5166 ns/op
+OverheadActual 14: 32768 op, 83221.00 ns, 2.5397 ns/op
+OverheadActual 15: 32768 op, 82467.00 ns, 2.5167 ns/op
+OverheadActual 16: 32768 op, 83134.00 ns, 2.5370 ns/op
+OverheadActual 17: 32768 op, 82466.00 ns, 2.5167 ns/op
+OverheadActual 18: 32768 op, 83508.00 ns, 2.5485 ns/op
+OverheadActual 19: 32768 op, 82528.00 ns, 2.5186 ns/op
+OverheadActual 20: 32768 op, 83410.00 ns, 2.5455 ns/op
+
+WorkloadWarmup 1: 32768 op, 852583277.00 ns, 26.0188 us/op
+WorkloadWarmup 2: 32768 op, 828279245.00 ns, 25.2771 us/op
+WorkloadWarmup 3: 32768 op, 822181143.00 ns, 25.0910 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 829956303.00 ns, 25.3283 us/op
+WorkloadActual 2: 32768 op, 852852412.00 ns, 26.0270 us/op
+WorkloadActual 3: 32768 op, 830870245.00 ns, 25.3561 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 829872996.00 ns, 25.3257 us/op
+WorkloadResult 2: 32768 op, 852769105.00 ns, 26.0244 us/op
+WorkloadResult 3: 32768 op, 830786938.00 ns, 25.3536 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 391791 has exited with code 0.
+
+Mean = 25.568 μs, StdErr = 0.228 μs (0.89%), N = 3, StdDev = 0.396 μs
+Min = 25.326 μs, Q1 = 25.340 μs, Median = 25.354 μs, Q3 = 25.689 μs, Max = 26.024 μs
+IQR = 0.349 μs, LowerFence = 24.816 μs, UpperFence = 26.213 μs
+ConfidenceInterval = [18.351 μs; 32.785 μs] (CI 99.9%), Margin = 7.217 μs (28.23% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 8 (72.7 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck --job ShortRun --benchmarkId 3 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 257456.00 ns, 257.4560 us/op
+WorkloadJitting 1: 1 op, 3011508.00 ns, 3.0115 ms/op
+
+OverheadJitting 2: 16 op, 503265.00 ns, 31.4541 us/op
+WorkloadJitting 2: 16 op, 1642673.00 ns, 102.6671 us/op
+
+WorkloadPilot 1: 16 op, 1140120.00 ns, 71.2575 us/op
+WorkloadPilot 2: 32 op, 2193088.00 ns, 68.5340 us/op
+WorkloadPilot 3: 64 op, 4544754.00 ns, 71.0118 us/op
+WorkloadPilot 4: 128 op, 8730533.00 ns, 68.2073 us/op
+WorkloadPilot 5: 256 op, 17128828.00 ns, 66.9095 us/op
+WorkloadPilot 6: 512 op, 33905826.00 ns, 66.2223 us/op
+WorkloadPilot 7: 1024 op, 72669630.00 ns, 70.9664 us/op
+WorkloadPilot 8: 2048 op, 84521646.00 ns, 41.2703 us/op
+WorkloadPilot 9: 4096 op, 106798789.00 ns, 26.0739 us/op
+WorkloadPilot 10: 8192 op, 211763371.00 ns, 25.8500 us/op
+WorkloadPilot 11: 16384 op, 422321338.00 ns, 25.7764 us/op
+WorkloadPilot 12: 32768 op, 844768288.00 ns, 25.7803 us/op
+
+OverheadWarmup 1: 32768 op, 90449.00 ns, 2.7603 ns/op
+OverheadWarmup 2: 32768 op, 82635.00 ns, 2.5218 ns/op
+OverheadWarmup 3: 32768 op, 93696.00 ns, 2.8594 ns/op
+OverheadWarmup 4: 32768 op, 82344.00 ns, 2.5129 ns/op
+OverheadWarmup 5: 32768 op, 83828.00 ns, 2.5582 ns/op
+OverheadWarmup 6: 32768 op, 96176.00 ns, 2.9351 ns/op
+OverheadWarmup 7: 32768 op, 83251.00 ns, 2.5406 ns/op
+
+OverheadActual 1: 32768 op, 82997.00 ns, 2.5329 ns/op
+OverheadActual 2: 32768 op, 83541.00 ns, 2.5495 ns/op
+OverheadActual 3: 32768 op, 83020.00 ns, 2.5336 ns/op
+OverheadActual 4: 32768 op, 84004.00 ns, 2.5636 ns/op
+OverheadActual 5: 32768 op, 87526.00 ns, 2.6711 ns/op
+OverheadActual 6: 32768 op, 83299.00 ns, 2.5421 ns/op
+OverheadActual 7: 32768 op, 82369.00 ns, 2.5137 ns/op
+OverheadActual 8: 32768 op, 88044.00 ns, 2.6869 ns/op
+OverheadActual 9: 32768 op, 82305.00 ns, 2.5117 ns/op
+OverheadActual 10: 32768 op, 83103.00 ns, 2.5361 ns/op
+OverheadActual 11: 32768 op, 82423.00 ns, 2.5154 ns/op
+OverheadActual 12: 32768 op, 83069.00 ns, 2.5351 ns/op
+OverheadActual 13: 32768 op, 85770.00 ns, 2.6175 ns/op
+OverheadActual 14: 32768 op, 83022.00 ns, 2.5336 ns/op
+OverheadActual 15: 32768 op, 82426.00 ns, 2.5154 ns/op
+
+WorkloadWarmup 1: 32768 op, 855286085.00 ns, 26.1013 us/op
+WorkloadWarmup 2: 32768 op, 864919781.00 ns, 26.3953 us/op
+WorkloadWarmup 3: 32768 op, 853101132.00 ns, 26.0346 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 845733589.00 ns, 25.8097 us/op
+WorkloadActual 2: 32768 op, 846265863.00 ns, 25.8260 us/op
+WorkloadActual 3: 32768 op, 847258441.00 ns, 25.8563 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 845650520.00 ns, 25.8072 us/op
+WorkloadResult 2: 32768 op, 846182794.00 ns, 25.8234 us/op
+WorkloadResult 3: 32768 op, 847175372.00 ns, 25.8537 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 392072 has exited with code 0.
+
+Mean = 25.828 μs, StdErr = 0.014 μs (0.05%), N = 3, StdDev = 0.024 μs
+Min = 25.807 μs, Q1 = 25.815 μs, Median = 25.823 μs, Q3 = 25.839 μs, Max = 25.854 μs
+IQR = 0.023 μs, LowerFence = 25.780 μs, UpperFence = 25.873 μs
+ConfidenceInterval = [25.397 μs; 26.259 μs] (CI 99.9%), Margin = 0.431 μs (1.67% of Mean)
+Skewness = 0.19, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 7 (63.6 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck --job ShortRun --benchmarkId 4 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 246863.00 ns, 246.8630 us/op
+WorkloadJitting 1: 1 op, 3055204.00 ns, 3.0552 ms/op
+
+OverheadJitting 2: 16 op, 529619.00 ns, 33.1012 us/op
+WorkloadJitting 2: 16 op, 1657965.00 ns, 103.6228 us/op
+
+WorkloadPilot 1: 16 op, 1161853.00 ns, 72.6158 us/op
+WorkloadPilot 2: 32 op, 2236207.00 ns, 69.8815 us/op
+WorkloadPilot 3: 64 op, 5046709.00 ns, 78.8548 us/op
+WorkloadPilot 4: 128 op, 8915412.00 ns, 69.6517 us/op
+WorkloadPilot 5: 256 op, 17833125.00 ns, 69.6606 us/op
+WorkloadPilot 6: 512 op, 35955696.00 ns, 70.2260 us/op
+WorkloadPilot 7: 1024 op, 92097824.00 ns, 89.9393 us/op
+WorkloadPilot 8: 2048 op, 53470887.00 ns, 26.1088 us/op
+WorkloadPilot 9: 4096 op, 104618650.00 ns, 25.5417 us/op
+WorkloadPilot 10: 8192 op, 206557366.00 ns, 25.2145 us/op
+WorkloadPilot 11: 16384 op, 413699349.00 ns, 25.2502 us/op
+WorkloadPilot 12: 32768 op, 830294036.00 ns, 25.3386 us/op
+
+OverheadWarmup 1: 32768 op, 84919.00 ns, 2.5915 ns/op
+OverheadWarmup 2: 32768 op, 82858.00 ns, 2.5286 ns/op
+OverheadWarmup 3: 32768 op, 83519.00 ns, 2.5488 ns/op
+OverheadWarmup 4: 32768 op, 82571.00 ns, 2.5199 ns/op
+OverheadWarmup 5: 32768 op, 94930.00 ns, 2.8970 ns/op
+OverheadWarmup 6: 32768 op, 82365.00 ns, 2.5136 ns/op
+
+OverheadActual 1: 32768 op, 83793.00 ns, 2.5572 ns/op
+OverheadActual 2: 32768 op, 96315.00 ns, 2.9393 ns/op
+OverheadActual 3: 32768 op, 84414.00 ns, 2.5761 ns/op
+OverheadActual 4: 32768 op, 82524.00 ns, 2.5184 ns/op
+OverheadActual 5: 32768 op, 83403.00 ns, 2.5453 ns/op
+OverheadActual 6: 32768 op, 82465.00 ns, 2.5166 ns/op
+OverheadActual 7: 32768 op, 94130.00 ns, 2.8726 ns/op
+OverheadActual 8: 32768 op, 82437.00 ns, 2.5158 ns/op
+OverheadActual 9: 32768 op, 83167.00 ns, 2.5381 ns/op
+OverheadActual 10: 32768 op, 92651.00 ns, 2.8275 ns/op
+OverheadActual 11: 32768 op, 82959.00 ns, 2.5317 ns/op
+OverheadActual 12: 32768 op, 82441.00 ns, 2.5159 ns/op
+OverheadActual 13: 32768 op, 83088.00 ns, 2.5356 ns/op
+OverheadActual 14: 32768 op, 82866.00 ns, 2.5289 ns/op
+OverheadActual 15: 32768 op, 83339.00 ns, 2.5433 ns/op
+
+WorkloadWarmup 1: 32768 op, 840674955.00 ns, 25.6554 us/op
+WorkloadWarmup 2: 32768 op, 834199174.00 ns, 25.4577 us/op
+WorkloadWarmup 3: 32768 op, 826944396.00 ns, 25.2363 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 851602436.00 ns, 25.9888 us/op
+WorkloadActual 2: 32768 op, 858261950.00 ns, 26.1921 us/op
+WorkloadActual 3: 32768 op, 849271083.00 ns, 25.9177 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 851519269.00 ns, 25.9863 us/op
+WorkloadResult 2: 32768 op, 858178783.00 ns, 26.1895 us/op
+WorkloadResult 3: 32768 op, 849187916.00 ns, 25.9152 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 392251 has exited with code 0.
+
+Mean = 26.030 μs, StdErr = 0.082 μs (0.32%), N = 3, StdDev = 0.142 μs
+Min = 25.915 μs, Q1 = 25.951 μs, Median = 25.986 μs, Q3 = 26.088 μs, Max = 26.190 μs
+IQR = 0.137 μs, LowerFence = 25.745 μs, UpperFence = 26.294 μs
+ConfidenceInterval = [23.433 μs; 28.628 μs] (CI 99.9%), Margin = 2.598 μs (9.98% of Mean)
+Skewness = 0.28, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 6 (54.5 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripWhitespace_Benchmark --job ShortRun --benchmarkId 5 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 289113.00 ns, 289.1130 us/op
+WorkloadJitting 1: 1 op, 12486581.00 ns, 12.4866 ms/op
+
+OverheadJitting 2: 16 op, 705072.00 ns, 44.0670 us/op
+WorkloadJitting 2: 16 op, 850502.00 ns, 53.1564 us/op
+
+WorkloadPilot 1: 16 op, 48473.00 ns, 3.0296 us/op
+WorkloadPilot 2: 32 op, 65791.00 ns, 2.0560 us/op
+WorkloadPilot 3: 64 op, 127686.00 ns, 1.9951 us/op
+WorkloadPilot 4: 128 op, 211395.00 ns, 1.6515 us/op
+WorkloadPilot 5: 256 op, 410379.00 ns, 1.6030 us/op
+WorkloadPilot 6: 512 op, 805350.00 ns, 1.5729 us/op
+WorkloadPilot 7: 1024 op, 1639824.00 ns, 1.6014 us/op
+WorkloadPilot 8: 2048 op, 3380426.00 ns, 1.6506 us/op
+WorkloadPilot 9: 4096 op, 6461801.00 ns, 1.5776 us/op
+WorkloadPilot 10: 8192 op, 12752536.00 ns, 1.5567 us/op
+WorkloadPilot 11: 16384 op, 25421378.00 ns, 1.5516 us/op
+WorkloadPilot 12: 32768 op, 50787774.00 ns, 1.5499 us/op
+WorkloadPilot 13: 65536 op, 128355667.00 ns, 1.9586 us/op
+WorkloadPilot 14: 131072 op, 92313151.00 ns, 704.2934 ns/op
+WorkloadPilot 15: 262144 op, 177300745.00 ns, 676.3487 ns/op
+WorkloadPilot 16: 524288 op, 349050186.00 ns, 665.7604 ns/op
+WorkloadPilot 17: 1048576 op, 710691047.00 ns, 677.7678 ns/op
+
+OverheadWarmup 1: 1048576 op, 5408705.00 ns, 5.1581 ns/op
+OverheadWarmup 2: 1048576 op, 4734414.00 ns, 4.5151 ns/op
+OverheadWarmup 3: 1048576 op, 4752981.00 ns, 4.5328 ns/op
+OverheadWarmup 4: 1048576 op, 5268403.00 ns, 5.0243 ns/op
+OverheadWarmup 5: 1048576 op, 5586314.00 ns, 5.3275 ns/op
+OverheadWarmup 6: 1048576 op, 5623146.00 ns, 5.3626 ns/op
+OverheadWarmup 7: 1048576 op, 4895023.00 ns, 4.6683 ns/op
+OverheadWarmup 8: 1048576 op, 5347981.00 ns, 5.1002 ns/op
+OverheadWarmup 9: 1048576 op, 5189132.00 ns, 4.9487 ns/op
+
+OverheadActual 1: 1048576 op, 5028246.00 ns, 4.7953 ns/op
+OverheadActual 2: 1048576 op, 5472457.00 ns, 5.2189 ns/op
+OverheadActual 3: 1048576 op, 5606309.00 ns, 5.3466 ns/op
+OverheadActual 4: 1048576 op, 5423770.00 ns, 5.1725 ns/op
+OverheadActual 5: 1048576 op, 4788068.00 ns, 4.5663 ns/op
+OverheadActual 6: 1048576 op, 4819579.00 ns, 4.5963 ns/op
+OverheadActual 7: 1048576 op, 5052339.00 ns, 4.8183 ns/op
+OverheadActual 8: 1048576 op, 4770460.00 ns, 4.5495 ns/op
+OverheadActual 9: 1048576 op, 5403926.00 ns, 5.1536 ns/op
+OverheadActual 10: 1048576 op, 4666081.00 ns, 4.4499 ns/op
+OverheadActual 11: 1048576 op, 4994370.00 ns, 4.7630 ns/op
+OverheadActual 12: 1048576 op, 5086106.00 ns, 4.8505 ns/op
+OverheadActual 13: 1048576 op, 4744771.00 ns, 4.5250 ns/op
+OverheadActual 14: 1048576 op, 5442308.00 ns, 5.1902 ns/op
+OverheadActual 15: 1048576 op, 4786314.00 ns, 4.5646 ns/op
+OverheadActual 16: 1048576 op, 4713366.00 ns, 4.4950 ns/op
+OverheadActual 17: 1048576 op, 5252322.00 ns, 5.0090 ns/op
+OverheadActual 18: 1048576 op, 5123232.00 ns, 4.8859 ns/op
+OverheadActual 19: 1048576 op, 4700443.00 ns, 4.4827 ns/op
+OverheadActual 20: 1048576 op, 4728392.00 ns, 4.5093 ns/op
+
+WorkloadWarmup 1: 1048576 op, 756236291.00 ns, 721.2031 ns/op
+WorkloadWarmup 2: 1048576 op, 721189324.00 ns, 687.7797 ns/op
+WorkloadWarmup 3: 1048576 op, 704226119.00 ns, 671.6024 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 699710490.00 ns, 667.2959 ns/op
+WorkloadActual 2: 1048576 op, 696737763.00 ns, 664.4609 ns/op
+WorkloadActual 3: 1048576 op, 696468031.00 ns, 664.2037 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 694699182.00 ns, 662.5168 ns/op
+WorkloadResult 2: 1048576 op, 691726455.00 ns, 659.6818 ns/op
+WorkloadResult 3: 1048576 op, 691456723.00 ns, 659.4245 ns/op
+// GC: 3 0 0 67109280 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 392524 has exited with code 0.
+
+Mean = 660.541 ns, StdErr = 0.991 ns (0.15%), N = 3, StdDev = 1.716 ns
+Min = 659.425 ns, Q1 = 659.553 ns, Median = 659.682 ns, Q3 = 661.099 ns, Max = 662.517 ns
+IQR = 1.546 ns, LowerFence = 657.234 ns, UpperFence = 663.418 ns
+ConfidenceInterval = [629.237 ns; 691.845 ns] (CI 99.9%), Margin = 31.304 ns (4.74% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 5 (45.5 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.GetFileExtension_Benchmark --job ShortRun --benchmarkId 6 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 374223.00 ns, 374.2230 us/op
+WorkloadJitting 1: 1 op, 17001273.00 ns, 17.0013 ms/op
+
+OverheadJitting 2: 16 op, 674959.00 ns, 42.1849 us/op
+WorkloadJitting 2: 16 op, 792092.00 ns, 49.5058 us/op
+
+WorkloadPilot 1: 16 op, 42610.00 ns, 2.6631 us/op
+WorkloadPilot 2: 32 op, 53676.00 ns, 1.6774 us/op
+WorkloadPilot 3: 64 op, 91399.00 ns, 1.4281 us/op
+WorkloadPilot 4: 128 op, 177210.00 ns, 1.3845 us/op
+WorkloadPilot 5: 256 op, 461623.00 ns, 1.8032 us/op
+WorkloadPilot 6: 512 op, 483362.00 ns, 944.0664 ns/op
+WorkloadPilot 7: 1024 op, 1052759.00 ns, 1.0281 us/op
+WorkloadPilot 8: 2048 op, 1992078.00 ns, 972.6943 ns/op
+WorkloadPilot 9: 4096 op, 4380253.00 ns, 1.0694 us/op
+WorkloadPilot 10: 8192 op, 9817378.00 ns, 1.1984 us/op
+WorkloadPilot 11: 16384 op, 16290359.00 ns, 994.2846 ns/op
+WorkloadPilot 12: 32768 op, 32146268.00 ns, 981.0262 ns/op
+WorkloadPilot 13: 65536 op, 65631504.00 ns, 1.0015 us/op
+WorkloadPilot 14: 131072 op, 166369147.00 ns, 1.2693 us/op
+WorkloadPilot 15: 262144 op, 133859918.00 ns, 510.6351 ns/op
+WorkloadPilot 16: 524288 op, 243844237.00 ns, 465.0960 ns/op
+WorkloadPilot 17: 1048576 op, 493953502.00 ns, 471.0708 ns/op
+WorkloadPilot 18: 2097152 op, 985217856.00 ns, 469.7885 ns/op
+
+OverheadWarmup 1: 2097152 op, 10261032.00 ns, 4.8928 ns/op
+OverheadWarmup 2: 2097152 op, 10273063.00 ns, 4.8986 ns/op
+OverheadWarmup 3: 2097152 op, 9936683.00 ns, 4.7382 ns/op
+OverheadWarmup 4: 2097152 op, 10198202.00 ns, 4.8629 ns/op
+OverheadWarmup 5: 2097152 op, 9893948.00 ns, 4.7178 ns/op
+
+OverheadActual 1: 2097152 op, 10204061.00 ns, 4.8657 ns/op
+OverheadActual 2: 2097152 op, 10339398.00 ns, 4.9302 ns/op
+OverheadActual 3: 2097152 op, 10206386.00 ns, 4.8668 ns/op
+OverheadActual 4: 2097152 op, 10038270.00 ns, 4.7866 ns/op
+OverheadActual 5: 2097152 op, 10338431.00 ns, 4.9297 ns/op
+OverheadActual 6: 2097152 op, 10223929.00 ns, 4.8751 ns/op
+OverheadActual 7: 2097152 op, 10048753.00 ns, 4.7916 ns/op
+OverheadActual 8: 2097152 op, 10310906.00 ns, 4.9166 ns/op
+OverheadActual 9: 2097152 op, 9897000.00 ns, 4.7193 ns/op
+OverheadActual 10: 2097152 op, 10241384.00 ns, 4.8835 ns/op
+OverheadActual 11: 2097152 op, 10072985.00 ns, 4.8032 ns/op
+OverheadActual 12: 2097152 op, 9929535.00 ns, 4.7348 ns/op
+OverheadActual 13: 2097152 op, 9959168.00 ns, 4.7489 ns/op
+OverheadActual 14: 2097152 op, 9925619.00 ns, 4.7329 ns/op
+OverheadActual 15: 2097152 op, 9868258.00 ns, 4.7056 ns/op
+
+WorkloadWarmup 1: 2097152 op, 972180103.00 ns, 463.5716 ns/op
+WorkloadWarmup 2: 2097152 op, 969383758.00 ns, 462.2382 ns/op
+WorkloadWarmup 3: 2097152 op, 970435446.00 ns, 462.7397 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 2097152 op, 996136947.00 ns, 474.9951 ns/op
+WorkloadActual 2: 2097152 op, 971644395.00 ns, 463.3162 ns/op
+WorkloadActual 3: 2097152 op, 980302509.00 ns, 467.4447 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 2097152 op, 986063962.00 ns, 470.1919 ns/op
+WorkloadResult 2: 2097152 op, 961571410.00 ns, 458.5130 ns/op
+WorkloadResult 3: 2097152 op, 970229524.00 ns, 462.6415 ns/op
+// GC: 67 0 0 1157627904 2097152
+// Threading: 0 0 2097152
+
+// AfterAll
+// Benchmark Process 392709 has exited with code 0.
+
+Mean = 463.782 ns, StdErr = 3.419 ns (0.74%), N = 3, StdDev = 5.922 ns
+Min = 458.513 ns, Q1 = 460.577 ns, Median = 462.641 ns, Q3 = 466.417 ns, Max = 470.192 ns
+IQR = 5.839 ns, LowerFence = 451.818 ns, UpperFence = 475.176 ns
+ConfidenceInterval = [355.735 ns; 571.830 ns] (CI 99.9%), Margin = 108.047 ns (23.30% of Mean)
+Skewness = 0.19, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 4 (36.4 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripHtml_Benchmark --job ShortRun --benchmarkId 7 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 280485.00 ns, 280.4850 us/op
+WorkloadJitting 1: 1 op, 18693975.00 ns, 18.6940 ms/op
+
+OverheadJitting 2: 16 op, 680487.00 ns, 42.5304 us/op
+WorkloadJitting 2: 16 op, 859042.00 ns, 53.6901 us/op
+
+WorkloadPilot 1: 16 op, 41865.00 ns, 2.6166 us/op
+WorkloadPilot 2: 32 op, 60300.00 ns, 1.8844 us/op
+WorkloadPilot 3: 64 op, 99663.00 ns, 1.5572 us/op
+WorkloadPilot 4: 128 op, 215976.00 ns, 1.6873 us/op
+WorkloadPilot 5: 256 op, 413002.00 ns, 1.6133 us/op
+WorkloadPilot 6: 512 op, 737815.00 ns, 1.4410 us/op
+WorkloadPilot 7: 1024 op, 1471671.00 ns, 1.4372 us/op
+WorkloadPilot 8: 2048 op, 2936383.00 ns, 1.4338 us/op
+WorkloadPilot 9: 4096 op, 5769008.00 ns, 1.4084 us/op
+WorkloadPilot 10: 8192 op, 11302770.00 ns, 1.3797 us/op
+WorkloadPilot 11: 16384 op, 22588711.00 ns, 1.3787 us/op
+WorkloadPilot 12: 32768 op, 44946158.00 ns, 1.3716 us/op
+WorkloadPilot 13: 65536 op, 86788925.00 ns, 1.3243 us/op
+WorkloadPilot 14: 131072 op, 99999263.00 ns, 762.9338 ns/op
+WorkloadPilot 15: 262144 op, 201108898.00 ns, 767.1696 ns/op
+WorkloadPilot 16: 524288 op, 407024548.00 ns, 776.3377 ns/op
+WorkloadPilot 17: 1048576 op, 787486124.00 ns, 751.0053 ns/op
+
+OverheadWarmup 1: 1048576 op, 4997558.00 ns, 4.7660 ns/op
+OverheadWarmup 2: 1048576 op, 4632789.00 ns, 4.4182 ns/op
+OverheadWarmup 3: 1048576 op, 4669385.00 ns, 4.4531 ns/op
+OverheadWarmup 4: 1048576 op, 4987004.00 ns, 4.7560 ns/op
+OverheadWarmup 5: 1048576 op, 4647014.00 ns, 4.4317 ns/op
+OverheadWarmup 6: 1048576 op, 4654266.00 ns, 4.4387 ns/op
+OverheadWarmup 7: 1048576 op, 5156661.00 ns, 4.9178 ns/op
+OverheadWarmup 8: 1048576 op, 4659484.00 ns, 4.4436 ns/op
+
+OverheadActual 1: 1048576 op, 4635903.00 ns, 4.4211 ns/op
+OverheadActual 2: 1048576 op, 5046191.00 ns, 4.8124 ns/op
+OverheadActual 3: 1048576 op, 4741819.00 ns, 4.5222 ns/op
+OverheadActual 4: 1048576 op, 4938922.00 ns, 4.7101 ns/op
+OverheadActual 5: 1048576 op, 4656057.00 ns, 4.4404 ns/op
+OverheadActual 6: 1048576 op, 4651489.00 ns, 4.4360 ns/op
+OverheadActual 7: 1048576 op, 4787908.00 ns, 4.5661 ns/op
+OverheadActual 8: 1048576 op, 4627311.00 ns, 4.4129 ns/op
+OverheadActual 9: 1048576 op, 4667656.00 ns, 4.4514 ns/op
+OverheadActual 10: 1048576 op, 4961130.00 ns, 4.7313 ns/op
+OverheadActual 11: 1048576 op, 4640319.00 ns, 4.4254 ns/op
+OverheadActual 12: 1048576 op, 4698470.00 ns, 4.4808 ns/op
+OverheadActual 13: 1048576 op, 5047598.00 ns, 4.8138 ns/op
+OverheadActual 14: 1048576 op, 4636324.00 ns, 4.4215 ns/op
+OverheadActual 15: 1048576 op, 4636547.00 ns, 4.4218 ns/op
+
+WorkloadWarmup 1: 1048576 op, 802907365.00 ns, 765.7121 ns/op
+WorkloadWarmup 2: 1048576 op, 790778489.00 ns, 754.1451 ns/op
+WorkloadWarmup 3: 1048576 op, 778317089.00 ns, 742.2610 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 769123981.00 ns, 733.4938 ns/op
+WorkloadActual 2: 1048576 op, 771083043.00 ns, 735.3621 ns/op
+WorkloadActual 3: 1048576 op, 782371249.00 ns, 746.1274 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 764456325.00 ns, 729.0424 ns/op
+WorkloadResult 2: 1048576 op, 766415387.00 ns, 730.9107 ns/op
+WorkloadResult 3: 1048576 op, 777703593.00 ns, 741.6759 ns/op
+// GC: 2 0 0 50331960 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 393003 has exited with code 0.
+
+Mean = 733.876 ns, StdErr = 3.937 ns (0.54%), N = 3, StdDev = 6.819 ns
+Min = 729.042 ns, Q1 = 729.977 ns, Median = 730.911 ns, Q3 = 736.293 ns, Max = 741.676 ns
+IQR = 6.317 ns, LowerFence = 720.501 ns, UpperFence = 745.768 ns
+ConfidenceInterval = [609.473 ns; 858.279 ns] (CI 99.9%), Margin = 124.403 ns (16.95% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 3 (27.3 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsLowerCase_Benchmark --job ShortRun --benchmarkId 8 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 269013.00 ns, 269.0130 us/op
+WorkloadJitting 1: 1 op, 3560811.00 ns, 3.5608 ms/op
+
+OverheadJitting 2: 16 op, 486242.00 ns, 30.3901 us/op
+WorkloadJitting 2: 16 op, 508247.00 ns, 31.7654 us/op
+
+WorkloadPilot 1: 16 op, 6500.00 ns, 406.2500 ns/op
+WorkloadPilot 2: 32 op, 6213.00 ns, 194.1563 ns/op
+WorkloadPilot 3: 64 op, 5214.00 ns, 81.4688 ns/op
+WorkloadPilot 4: 128 op, 24679.00 ns, 192.8047 ns/op
+WorkloadPilot 5: 256 op, 33964.00 ns, 132.6719 ns/op
+WorkloadPilot 6: 512 op, 38090.00 ns, 74.3945 ns/op
+WorkloadPilot 7: 1024 op, 102643.00 ns, 100.2373 ns/op
+WorkloadPilot 8: 2048 op, 153037.00 ns, 74.7251 ns/op
+WorkloadPilot 9: 4096 op, 355022.00 ns, 86.6753 ns/op
+WorkloadPilot 10: 8192 op, 494356.00 ns, 60.3462 ns/op
+WorkloadPilot 11: 16384 op, 1002486.00 ns, 61.1869 ns/op
+WorkloadPilot 12: 32768 op, 2027516.00 ns, 61.8749 ns/op
+WorkloadPilot 13: 65536 op, 4068819.00 ns, 62.0853 ns/op
+WorkloadPilot 14: 131072 op, 8184834.00 ns, 62.4453 ns/op
+WorkloadPilot 15: 262144 op, 16507740.00 ns, 62.9720 ns/op
+WorkloadPilot 16: 524288 op, 26860816.00 ns, 51.2329 ns/op
+WorkloadPilot 17: 1048576 op, 48155982.00 ns, 45.9251 ns/op
+WorkloadPilot 18: 2097152 op, 68238857.00 ns, 32.5388 ns/op
+WorkloadPilot 19: 4194304 op, 115097412.00 ns, 27.4414 ns/op
+WorkloadPilot 20: 8388608 op, 225933899.00 ns, 26.9334 ns/op
+WorkloadPilot 21: 16777216 op, 438193574.00 ns, 26.1184 ns/op
+WorkloadPilot 22: 33554432 op, 877136923.00 ns, 26.1407 ns/op
+
+OverheadWarmup 1: 33554432 op, 85770198.00 ns, 2.5562 ns/op
+OverheadWarmup 2: 33554432 op, 86324404.00 ns, 2.5727 ns/op
+OverheadWarmup 3: 33554432 op, 71460830.00 ns, 2.1297 ns/op
+OverheadWarmup 4: 33554432 op, 65156944.00 ns, 1.9418 ns/op
+OverheadWarmup 5: 33554432 op, 65734932.00 ns, 1.9591 ns/op
+OverheadWarmup 6: 33554432 op, 65445754.00 ns, 1.9504 ns/op
+
+OverheadActual 1: 33554432 op, 65594194.00 ns, 1.9549 ns/op
+OverheadActual 2: 33554432 op, 64894583.00 ns, 1.9340 ns/op
+OverheadActual 3: 33554432 op, 64454033.00 ns, 1.9209 ns/op
+OverheadActual 4: 33554432 op, 64539918.00 ns, 1.9234 ns/op
+OverheadActual 5: 33554432 op, 64496046.00 ns, 1.9221 ns/op
+OverheadActual 6: 33554432 op, 64570323.00 ns, 1.9243 ns/op
+OverheadActual 7: 33554432 op, 64513749.00 ns, 1.9227 ns/op
+OverheadActual 8: 33554432 op, 64353775.00 ns, 1.9179 ns/op
+OverheadActual 9: 33554432 op, 64289648.00 ns, 1.9160 ns/op
+OverheadActual 10: 33554432 op, 64321525.00 ns, 1.9169 ns/op
+OverheadActual 11: 33554432 op, 64307077.00 ns, 1.9165 ns/op
+OverheadActual 12: 33554432 op, 64889728.00 ns, 1.9339 ns/op
+OverheadActual 13: 33554432 op, 65476712.00 ns, 1.9514 ns/op
+OverheadActual 14: 33554432 op, 64550152.00 ns, 1.9237 ns/op
+OverheadActual 15: 33554432 op, 64534182.00 ns, 1.9233 ns/op
+
+WorkloadWarmup 1: 33554432 op, 900463471.00 ns, 26.8359 ns/op
+WorkloadWarmup 2: 33554432 op, 905115554.00 ns, 26.9745 ns/op
+WorkloadWarmup 3: 33554432 op, 877766673.00 ns, 26.1595 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 33554432 op, 876753788.00 ns, 26.1293 ns/op
+WorkloadActual 2: 33554432 op, 911541077.00 ns, 27.1660 ns/op
+WorkloadActual 3: 33554432 op, 918798502.00 ns, 27.3823 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 33554432 op, 812219606.00 ns, 24.2060 ns/op
+WorkloadResult 2: 33554432 op, 847006895.00 ns, 25.2428 ns/op
+WorkloadResult 3: 33554432 op, 854264320.00 ns, 25.4591 ns/op
+// GC: 93 0 0 1610612736 33554432
+// Threading: 0 0 33554432
+
+// AfterAll
+// Benchmark Process 393291 has exited with code 0.
+
+Mean = 24.969 ns, StdErr = 0.387 ns (1.55%), N = 3, StdDev = 0.670 ns
+Min = 24.206 ns, Q1 = 24.724 ns, Median = 25.243 ns, Q3 = 25.351 ns, Max = 25.459 ns
+IQR = 0.627 ns, LowerFence = 23.785 ns, UpperFence = 26.291 ns
+ConfidenceInterval = [12.750 ns; 37.189 ns] (CI 99.9%), Margin = 12.219 ns (48.94% of Mean)
+Skewness = -0.34, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 2 (18.2 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsUpperCase_Benchmark --job ShortRun --benchmarkId 9 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 244918.00 ns, 244.9180 us/op
+WorkloadJitting 1: 1 op, 3642046.00 ns, 3.6420 ms/op
+
+OverheadJitting 2: 16 op, 508954.00 ns, 31.8096 us/op
+WorkloadJitting 2: 16 op, 511425.00 ns, 31.9641 us/op
+
+WorkloadPilot 1: 16 op, 5633.00 ns, 352.0625 ns/op
+WorkloadPilot 2: 32 op, 5578.00 ns, 174.3125 ns/op
+WorkloadPilot 3: 64 op, 5386.00 ns, 84.1563 ns/op
+WorkloadPilot 4: 128 op, 24481.00 ns, 191.2578 ns/op
+WorkloadPilot 5: 256 op, 32029.00 ns, 125.1133 ns/op
+WorkloadPilot 6: 512 op, 39433.00 ns, 77.0176 ns/op
+WorkloadPilot 7: 1024 op, 92288.00 ns, 90.1250 ns/op
+WorkloadPilot 8: 2048 op, 160147.00 ns, 78.1968 ns/op
+WorkloadPilot 9: 4096 op, 302639.00 ns, 73.8865 ns/op
+WorkloadPilot 10: 8192 op, 471848.00 ns, 57.5986 ns/op
+WorkloadPilot 11: 16384 op, 1025951.00 ns, 62.6191 ns/op
+WorkloadPilot 12: 32768 op, 2077000.00 ns, 63.3850 ns/op
+WorkloadPilot 13: 65536 op, 4053033.00 ns, 61.8444 ns/op
+WorkloadPilot 14: 131072 op, 7974007.00 ns, 60.8368 ns/op
+WorkloadPilot 15: 262144 op, 16825525.00 ns, 64.1843 ns/op
+WorkloadPilot 16: 524288 op, 27329884.00 ns, 52.1276 ns/op
+WorkloadPilot 17: 1048576 op, 48584204.00 ns, 46.3335 ns/op
+WorkloadPilot 18: 2097152 op, 67399231.00 ns, 32.1385 ns/op
+WorkloadPilot 19: 4194304 op, 111943457.00 ns, 26.6894 ns/op
+WorkloadPilot 20: 8388608 op, 226213967.00 ns, 26.9668 ns/op
+WorkloadPilot 21: 16777216 op, 444552125.00 ns, 26.4974 ns/op
+WorkloadPilot 22: 33554432 op, 899789141.00 ns, 26.8158 ns/op
+
+OverheadWarmup 1: 33554432 op, 85670620.00 ns, 2.5532 ns/op
+OverheadWarmup 2: 33554432 op, 86226891.00 ns, 2.5698 ns/op
+OverheadWarmup 3: 33554432 op, 72206401.00 ns, 2.1519 ns/op
+OverheadWarmup 4: 33554432 op, 65993162.00 ns, 1.9667 ns/op
+OverheadWarmup 5: 33554432 op, 65338342.00 ns, 1.9472 ns/op
+OverheadWarmup 6: 33554432 op, 65495755.00 ns, 1.9519 ns/op
+OverheadWarmup 7: 33554432 op, 66343802.00 ns, 1.9772 ns/op
+OverheadWarmup 8: 33554432 op, 65460359.00 ns, 1.9509 ns/op
+
+OverheadActual 1: 33554432 op, 65293737.00 ns, 1.9459 ns/op
+OverheadActual 2: 33554432 op, 65204105.00 ns, 1.9432 ns/op
+OverheadActual 3: 33554432 op, 65040779.00 ns, 1.9384 ns/op
+OverheadActual 4: 33554432 op, 65416581.00 ns, 1.9496 ns/op
+OverheadActual 5: 33554432 op, 65178287.00 ns, 1.9425 ns/op
+OverheadActual 6: 33554432 op, 65003320.00 ns, 1.9372 ns/op
+OverheadActual 7: 33554432 op, 65257439.00 ns, 1.9448 ns/op
+OverheadActual 8: 33554432 op, 64705100.00 ns, 1.9284 ns/op
+OverheadActual 9: 33554432 op, 64998490.00 ns, 1.9371 ns/op
+OverheadActual 10: 33554432 op, 65118244.00 ns, 1.9407 ns/op
+OverheadActual 11: 33554432 op, 64927036.00 ns, 1.9350 ns/op
+OverheadActual 12: 33554432 op, 65258724.00 ns, 1.9449 ns/op
+OverheadActual 13: 33554432 op, 66394620.00 ns, 1.9787 ns/op
+OverheadActual 14: 33554432 op, 65654316.00 ns, 1.9567 ns/op
+OverheadActual 15: 33554432 op, 64416565.00 ns, 1.9198 ns/op
+
+WorkloadWarmup 1: 33554432 op, 911081512.00 ns, 27.1523 ns/op
+WorkloadWarmup 2: 33554432 op, 915337090.00 ns, 27.2792 ns/op
+WorkloadWarmup 3: 33554432 op, 898902799.00 ns, 26.7894 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 33554432 op, 895167091.00 ns, 26.6781 ns/op
+WorkloadActual 2: 33554432 op, 921489202.00 ns, 27.4625 ns/op
+WorkloadActual 3: 33554432 op, 919939006.00 ns, 27.4163 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 33554432 op, 829988804.00 ns, 24.7356 ns/op
+WorkloadResult 2: 33554432 op, 856310915.00 ns, 25.5201 ns/op
+WorkloadResult 3: 33554432 op, 854760719.00 ns, 25.4739 ns/op
+// GC: 93 0 0 1610612736 33554432
+// Threading: 0 0 33554432
+
+// AfterAll
+// Benchmark Process 393605 has exited with code 0.
+
+Mean = 25.243 ns, StdErr = 0.254 ns (1.01%), N = 3, StdDev = 0.440 ns
+Min = 24.736 ns, Q1 = 25.105 ns, Median = 25.474 ns, Q3 = 25.497 ns, Max = 25.520 ns
+IQR = 0.392 ns, LowerFence = 24.516 ns, UpperFence = 26.085 ns
+ConfidenceInterval = [17.213 ns; 33.274 ns] (CI 99.9%), Margin = 8.030 ns (31.81% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 1 (9.1 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark --job ShortRun --benchmarkId 10 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 278385.00 ns, 278.3850 us/op
+WorkloadJitting 1: 1 op, 4801256.00 ns, 4.8013 ms/op
+
+OverheadJitting 2: 16 op, 699033.00 ns, 43.6896 us/op
+WorkloadJitting 2: 16 op, 791291.00 ns, 49.4557 us/op
+
+WorkloadPilot 1: 16 op, 73187.00 ns, 4.5742 us/op
+WorkloadPilot 2: 32 op, 102648.00 ns, 3.2078 us/op
+WorkloadPilot 3: 64 op, 212816.00 ns, 3.3253 us/op
+WorkloadPilot 4: 128 op, 393175.00 ns, 3.0717 us/op
+WorkloadPilot 5: 256 op, 645931.00 ns, 2.5232 us/op
+WorkloadPilot 6: 512 op, 1583677.00 ns, 3.0931 us/op
+WorkloadPilot 7: 1024 op, 3027921.00 ns, 2.9570 us/op
+WorkloadPilot 8: 2048 op, 5865374.00 ns, 2.8640 us/op
+WorkloadPilot 9: 4096 op, 11556083.00 ns, 2.8213 us/op
+WorkloadPilot 10: 8192 op, 23172548.00 ns, 2.8287 us/op
+WorkloadPilot 11: 16384 op, 43307548.00 ns, 2.6433 us/op
+WorkloadPilot 12: 32768 op, 58803638.00 ns, 1.7945 us/op
+WorkloadPilot 13: 65536 op, 41638431.00 ns, 635.3520 ns/op
+WorkloadPilot 14: 131072 op, 82321631.00 ns, 628.0642 ns/op
+WorkloadPilot 15: 262144 op, 158707170.00 ns, 605.4198 ns/op
+WorkloadPilot 16: 524288 op, 318017506.00 ns, 606.5703 ns/op
+WorkloadPilot 17: 1048576 op, 653173083.00 ns, 622.9144 ns/op
+
+OverheadWarmup 1: 1048576 op, 4640436.00 ns, 4.4255 ns/op
+OverheadWarmup 2: 1048576 op, 4646298.00 ns, 4.4311 ns/op
+OverheadWarmup 3: 1048576 op, 4642245.00 ns, 4.4272 ns/op
+OverheadWarmup 4: 1048576 op, 4655493.00 ns, 4.4398 ns/op
+OverheadWarmup 5: 1048576 op, 4678362.00 ns, 4.4616 ns/op
+OverheadWarmup 6: 1048576 op, 4647520.00 ns, 4.4322 ns/op
+
+OverheadActual 1: 1048576 op, 4644302.00 ns, 4.4292 ns/op
+OverheadActual 2: 1048576 op, 4663382.00 ns, 4.4473 ns/op
+OverheadActual 3: 1048576 op, 4630963.00 ns, 4.4164 ns/op
+OverheadActual 4: 1048576 op, 4638699.00 ns, 4.4238 ns/op
+OverheadActual 5: 1048576 op, 4625469.00 ns, 4.4112 ns/op
+OverheadActual 6: 1048576 op, 4656358.00 ns, 4.4406 ns/op
+OverheadActual 7: 1048576 op, 4641933.00 ns, 4.4269 ns/op
+OverheadActual 8: 1048576 op, 4649760.00 ns, 4.4344 ns/op
+OverheadActual 9: 1048576 op, 4637816.00 ns, 4.4230 ns/op
+OverheadActual 10: 1048576 op, 4656230.00 ns, 4.4405 ns/op
+OverheadActual 11: 1048576 op, 4632466.00 ns, 4.4179 ns/op
+OverheadActual 12: 1048576 op, 4642688.00 ns, 4.4276 ns/op
+OverheadActual 13: 1048576 op, 4648387.00 ns, 4.4330 ns/op
+OverheadActual 14: 1048576 op, 4650440.00 ns, 4.4350 ns/op
+OverheadActual 15: 1048576 op, 4636886.00 ns, 4.4221 ns/op
+
+WorkloadWarmup 1: 1048576 op, 648077625.00 ns, 618.0550 ns/op
+WorkloadWarmup 2: 1048576 op, 645249560.00 ns, 615.3579 ns/op
+WorkloadWarmup 3: 1048576 op, 631170993.00 ns, 601.9316 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 639425668.00 ns, 609.8038 ns/op
+WorkloadActual 2: 1048576 op, 652257178.00 ns, 622.0409 ns/op
+WorkloadActual 3: 1048576 op, 644070097.00 ns, 614.2331 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 634782980.00 ns, 605.3762 ns/op
+WorkloadResult 2: 1048576 op, 647614490.00 ns, 617.6133 ns/op
+WorkloadResult 3: 1048576 op, 639427409.00 ns, 609.8055 ns/op
+// GC: 79 0 0 1367343104 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 393896 has exited with code 0.
+
+Mean = 610.932 ns, StdErr = 3.577 ns (0.59%), N = 3, StdDev = 6.196 ns
+Min = 605.376 ns, Q1 = 607.591 ns, Median = 609.805 ns, Q3 = 613.709 ns, Max = 617.613 ns
+IQR = 6.119 ns, LowerFence = 598.413 ns, UpperFence = 622.887 ns
+ConfidenceInterval = [497.897 ns; 723.966 ns] (CI 99.9%), Margin = 113.034 ns (18.50% of Mean)
+Skewness = 0.18, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-07 21:43 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html
+
+// * Detailed results *
+StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 50.664 μs, StdErr = 0.087 μs (0.17%), N = 3, StdDev = 0.150 μs
+Min = 50.507 μs, Q1 = 50.592 μs, Median = 50.678 μs, Q3 = 50.742 μs, Max = 50.807 μs
+IQR = 0.150 μs, LowerFence = 50.367 μs, UpperFence = 50.967 μs
+ConfidenceInterval = [47.918 μs; 53.410 μs] (CI 99.9%), Margin = 2.746 μs (5.42% of Mean)
+Skewness = -0.09, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[50.370 μs ; 50.944 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 36.488 μs, StdErr = 0.278 μs (0.76%), N = 3, StdDev = 0.481 μs
+Min = 35.932 μs, Q1 = 36.344 μs, Median = 36.756 μs, Q3 = 36.765 μs, Max = 36.774 μs
+IQR = 0.421 μs, LowerFence = 35.713 μs, UpperFence = 37.396 μs
+ConfidenceInterval = [27.716 μs; 45.259 μs] (CI 99.9%), Margin = 8.772 μs (24.04% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[35.916 μs ; 36.791 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 25.568 μs, StdErr = 0.228 μs (0.89%), N = 3, StdDev = 0.396 μs
+Min = 25.326 μs, Q1 = 25.340 μs, Median = 25.354 μs, Q3 = 25.689 μs, Max = 26.024 μs
+IQR = 0.349 μs, LowerFence = 24.816 μs, UpperFence = 26.213 μs
+ConfidenceInterval = [18.351 μs; 32.785 μs] (CI 99.9%), Margin = 7.217 μs (28.23% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[25.315 μs ; 26.035 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 25.828 μs, StdErr = 0.014 μs (0.05%), N = 3, StdDev = 0.024 μs
+Min = 25.807 μs, Q1 = 25.815 μs, Median = 25.823 μs, Q3 = 25.839 μs, Max = 25.854 μs
+IQR = 0.023 μs, LowerFence = 25.780 μs, UpperFence = 25.873 μs
+ConfidenceInterval = [25.397 μs; 26.259 μs] (CI 99.9%), Margin = 0.431 μs (1.67% of Mean)
+Skewness = 0.19, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[25.786 μs ; 25.875 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 26.030 μs, StdErr = 0.082 μs (0.32%), N = 3, StdDev = 0.142 μs
+Min = 25.915 μs, Q1 = 25.951 μs, Median = 25.986 μs, Q3 = 26.088 μs, Max = 26.190 μs
+IQR = 0.137 μs, LowerFence = 25.745 μs, UpperFence = 26.294 μs
+ConfidenceInterval = [23.433 μs; 28.628 μs] (CI 99.9%), Margin = 2.598 μs (9.98% of Mean)
+Skewness = 0.28, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[25.786 μs ; 26.210 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 660.541 ns, StdErr = 0.991 ns (0.15%), N = 3, StdDev = 1.716 ns
+Min = 659.425 ns, Q1 = 659.553 ns, Median = 659.682 ns, Q3 = 661.099 ns, Max = 662.517 ns
+IQR = 1.546 ns, LowerFence = 657.234 ns, UpperFence = 663.418 ns
+ConfidenceInterval = [629.237 ns; 691.845 ns] (CI 99.9%), Margin = 31.304 ns (4.74% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[659.409 ns ; 662.532 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 463.782 ns, StdErr = 3.419 ns (0.74%), N = 3, StdDev = 5.922 ns
+Min = 458.513 ns, Q1 = 460.577 ns, Median = 462.641 ns, Q3 = 466.417 ns, Max = 470.192 ns
+IQR = 5.839 ns, LowerFence = 451.818 ns, UpperFence = 475.176 ns
+ConfidenceInterval = [355.735 ns; 571.830 ns] (CI 99.9%), Margin = 108.047 ns (23.30% of Mean)
+Skewness = 0.19, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[455.188 ns ; 465.967 ns) | @@
+[465.967 ns ; 475.582 ns) | @
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 733.876 ns, StdErr = 3.937 ns (0.54%), N = 3, StdDev = 6.819 ns
+Min = 729.042 ns, Q1 = 729.977 ns, Median = 730.911 ns, Q3 = 736.293 ns, Max = 741.676 ns
+IQR = 6.317 ns, LowerFence = 720.501 ns, UpperFence = 745.768 ns
+ConfidenceInterval = [609.473 ns; 858.279 ns] (CI 99.9%), Margin = 124.403 ns (16.95% of Mean)
+Skewness = 0.35, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[722.837 ns ; 747.882 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 24.969 ns, StdErr = 0.387 ns (1.55%), N = 3, StdDev = 0.670 ns
+Min = 24.206 ns, Q1 = 24.724 ns, Median = 25.243 ns, Q3 = 25.351 ns, Max = 25.459 ns
+IQR = 0.627 ns, LowerFence = 23.785 ns, UpperFence = 26.291 ns
+ConfidenceInterval = [12.750 ns; 37.189 ns] (CI 99.9%), Margin = 12.219 ns (48.94% of Mean)
+Skewness = -0.34, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[23.596 ns ; 24.741 ns) | @
+[24.741 ns ; 26.069 ns) | @@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 25.243 ns, StdErr = 0.254 ns (1.01%), N = 3, StdDev = 0.440 ns
+Min = 24.736 ns, Q1 = 25.105 ns, Median = 25.474 ns, Q3 = 25.497 ns, Max = 25.520 ns
+IQR = 0.392 ns, LowerFence = 24.516 ns, UpperFence = 26.085 ns
+ConfidenceInterval = [17.213 ns; 33.274 ns] (CI 99.9%), Margin = 8.030 ns (31.81% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[24.727 ns ; 25.528 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 610.932 ns, StdErr = 3.577 ns (0.59%), N = 3, StdDev = 6.196 ns
+Min = 605.376 ns, Q1 = 607.591 ns, Median = 609.805 ns, Q3 = 613.709 ns, Max = 617.613 ns
+IQR = 6.119 ns, LowerFence = 598.413 ns, UpperFence = 622.887 ns
+ConfidenceInterval = [497.897 ns; 723.966 ns] (CI 99.9%), Margin = 113.034 ns (18.50% of Mean)
+Skewness = 0.18, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[601.515 ns ; 623.252 ns) | @@@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100-rc.2.25502.107
+ [Host] : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+
+Job=ShortRun IterationCount=3 LaunchCount=1
+WarmupCount=3
+
+| Method | Mean | Error | StdDev | Gen0 | Allocated |
+|------------------------------------------------------ |-------------:|-------------:|-----------:|-------:|----------:|
+| Linq | 50,663.94 ns | 2,745.572 ns | 150.494 ns | 3.4180 | 59712 B |
+| SplitToHeapStrings | 36,487.59 ns | 8,771.897 ns | 480.817 ns | 2.5635 | 44592 B |
+| SplitToStackSpansWithoutEmptyCheckReversingListAsSpan | 25,567.92 ns | 7,217.372 ns | 395.608 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithoutEmptyCheck | 25,828.13 ns | 430.882 ns | 23.618 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithEmptyCheck | 26,030.33 ns | 2,597.723 ns | 142.390 ns | 0.9766 | 17128 B |
+| StripWhitespace_Benchmark | 660.54 ns | 31.304 ns | 1.716 ns | 0.0029 | 64 B |
+| GetFileExtension_Benchmark | 463.78 ns | 108.047 ns | 5.922 ns | 0.0319 | 552 B |
+| StripHtml_Benchmark | 733.88 ns | 124.403 ns | 6.819 ns | 0.0019 | 48 B |
+| IsLowerCase_Benchmark | 24.97 ns | 12.219 ns | 0.670 ns | 0.0028 | 48 B |
+| IsUpperCase_Benchmark | 25.24 ns | 8.030 ns | 0.440 ns | 0.0028 | 48 B |
+| ReplaceNonAlphanumericChars_String_Benchmark | 610.93 ns | 113.034 ns | 6.196 ns | 0.0753 | 1304 B |
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:01:28 (88.1 sec), executed benchmarks: 11
+
+Global total time: 00:03:10 (190.62 sec), executed benchmarks: 11
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-223616.log b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-223616.log
new file mode 100644
index 0000000000..bec8584af6
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-223616.log
@@ -0,0 +1,1187 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 11 benchmark(s) in total *****
+// ***** Building 1 exe(s) in Parallel: Start *****
+// start dotnet restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 3.7 sec and exited with 0
+// start dotnet build -c Release --no-restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/publish/" --output "/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1
+// command took 97.46 sec and exited with 0
+// ***** Done, took 00:01:41 (101.45 sec) *****
+// Found 11 benchmarks:
+// StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+// **************************
+// Benchmark: StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.Linq --job ShortRun --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 261958.00 ns, 261.9580 us/op
+WorkloadJitting 1: 1 op, 9240454.00 ns, 9.2405 ms/op
+
+OverheadJitting 2: 16 op, 509924.00 ns, 31.8703 us/op
+WorkloadJitting 2: 16 op, 3459191.00 ns, 216.1994 us/op
+
+WorkloadPilot 1: 16 op, 2917499.00 ns, 182.3437 us/op
+WorkloadPilot 2: 32 op, 5342053.00 ns, 166.9392 us/op
+WorkloadPilot 3: 64 op, 11676885.00 ns, 182.4513 us/op
+WorkloadPilot 4: 128 op, 23471669.00 ns, 183.3724 us/op
+WorkloadPilot 5: 256 op, 45505429.00 ns, 177.7556 us/op
+WorkloadPilot 6: 512 op, 108379096.00 ns, 211.6779 us/op
+WorkloadPilot 7: 1024 op, 55567536.00 ns, 54.2652 us/op
+WorkloadPilot 8: 2048 op, 104963355.00 ns, 51.2516 us/op
+WorkloadPilot 9: 4096 op, 210482732.00 ns, 51.3874 us/op
+WorkloadPilot 10: 8192 op, 420671757.00 ns, 51.3515 us/op
+WorkloadPilot 11: 16384 op, 841291544.00 ns, 51.3484 us/op
+
+OverheadWarmup 1: 16384 op, 54477.00 ns, 3.3250 ns/op
+OverheadWarmup 2: 16384 op, 46033.00 ns, 2.8096 ns/op
+OverheadWarmup 3: 16384 op, 41181.00 ns, 2.5135 ns/op
+OverheadWarmup 4: 16384 op, 41023.00 ns, 2.5038 ns/op
+OverheadWarmup 5: 16384 op, 42821.00 ns, 2.6136 ns/op
+OverheadWarmup 6: 16384 op, 41057.00 ns, 2.5059 ns/op
+OverheadWarmup 7: 16384 op, 42754.00 ns, 2.6095 ns/op
+OverheadWarmup 8: 16384 op, 41175.00 ns, 2.5131 ns/op
+
+OverheadActual 1: 16384 op, 43110.00 ns, 2.6312 ns/op
+OverheadActual 2: 16384 op, 41478.00 ns, 2.5316 ns/op
+OverheadActual 3: 16384 op, 41846.00 ns, 2.5541 ns/op
+OverheadActual 4: 16384 op, 41347.00 ns, 2.5236 ns/op
+OverheadActual 5: 16384 op, 42804.00 ns, 2.6125 ns/op
+OverheadActual 6: 16384 op, 41153.00 ns, 2.5118 ns/op
+OverheadActual 7: 16384 op, 41233.00 ns, 2.5167 ns/op
+OverheadActual 8: 16384 op, 41325.00 ns, 2.5223 ns/op
+OverheadActual 9: 16384 op, 42284.00 ns, 2.5808 ns/op
+OverheadActual 10: 16384 op, 41183.00 ns, 2.5136 ns/op
+OverheadActual 11: 16384 op, 41327.00 ns, 2.5224 ns/op
+OverheadActual 12: 16384 op, 41019.00 ns, 2.5036 ns/op
+OverheadActual 13: 16384 op, 42267.00 ns, 2.5798 ns/op
+OverheadActual 14: 16384 op, 41353.00 ns, 2.5240 ns/op
+OverheadActual 15: 16384 op, 41229.00 ns, 2.5164 ns/op
+
+WorkloadWarmup 1: 16384 op, 859759947.00 ns, 52.4756 us/op
+WorkloadWarmup 2: 16384 op, 862693473.00 ns, 52.6546 us/op
+WorkloadWarmup 3: 16384 op, 864880077.00 ns, 52.7881 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 840470359.00 ns, 51.2982 us/op
+WorkloadActual 2: 16384 op, 838307511.00 ns, 51.1662 us/op
+WorkloadActual 3: 16384 op, 837709253.00 ns, 51.1297 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 840429012.00 ns, 51.2957 us/op
+WorkloadResult 2: 16384 op, 838266164.00 ns, 51.1637 us/op
+WorkloadResult 3: 16384 op, 837667906.00 ns, 51.1272 us/op
+// GC: 56 0 0 978321408 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 515050 has exited with code 0.
+
+Mean = 51.196 μs, StdErr = 0.051 μs (0.10%), N = 3, StdDev = 0.089 μs
+Min = 51.127 μs, Q1 = 51.145 μs, Median = 51.164 μs, Q3 = 51.230 μs, Max = 51.296 μs
+IQR = 0.084 μs, LowerFence = 51.019 μs, UpperFence = 51.356 μs
+ConfidenceInterval = [49.578 μs; 52.813 μs] (CI 99.9%), Margin = 1.617 μs (3.16% of Mean)
+Skewness = 0.31, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 10 (90.9 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToHeapStrings --job ShortRun --benchmarkId 1 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 249073.00 ns, 249.0730 us/op
+WorkloadJitting 1: 1 op, 2523791.00 ns, 2.5238 ms/op
+
+OverheadJitting 2: 16 op, 508354.00 ns, 31.7721 us/op
+WorkloadJitting 2: 16 op, 1836564.00 ns, 114.7853 us/op
+
+WorkloadPilot 1: 16 op, 1369196.00 ns, 85.5748 us/op
+WorkloadPilot 2: 32 op, 2453586.00 ns, 76.6746 us/op
+WorkloadPilot 3: 64 op, 5182279.00 ns, 80.9731 us/op
+WorkloadPilot 4: 128 op, 10317917.00 ns, 80.6087 us/op
+WorkloadPilot 5: 256 op, 19907876.00 ns, 77.7651 us/op
+WorkloadPilot 6: 512 op, 35256021.00 ns, 68.8594 us/op
+WorkloadPilot 7: 1024 op, 105571104.00 ns, 103.0968 us/op
+WorkloadPilot 8: 2048 op, 75749941.00 ns, 36.9873 us/op
+WorkloadPilot 9: 4096 op, 149395108.00 ns, 36.4734 us/op
+WorkloadPilot 10: 8192 op, 302682602.00 ns, 36.9486 us/op
+WorkloadPilot 11: 16384 op, 601542701.00 ns, 36.7153 us/op
+
+OverheadWarmup 1: 16384 op, 66265.00 ns, 4.0445 ns/op
+OverheadWarmup 2: 16384 op, 41552.00 ns, 2.5361 ns/op
+OverheadWarmup 3: 16384 op, 41325.00 ns, 2.5223 ns/op
+OverheadWarmup 4: 16384 op, 41382.00 ns, 2.5258 ns/op
+OverheadWarmup 5: 16384 op, 42792.00 ns, 2.6118 ns/op
+OverheadWarmup 6: 16384 op, 41388.00 ns, 2.5261 ns/op
+OverheadWarmup 7: 16384 op, 41378.00 ns, 2.5255 ns/op
+OverheadWarmup 8: 16384 op, 54101.00 ns, 3.3021 ns/op
+OverheadWarmup 9: 16384 op, 42525.00 ns, 2.5955 ns/op
+
+OverheadActual 1: 16384 op, 41805.00 ns, 2.5516 ns/op
+OverheadActual 2: 16384 op, 41793.00 ns, 2.5508 ns/op
+OverheadActual 3: 16384 op, 41725.00 ns, 2.5467 ns/op
+OverheadActual 4: 16384 op, 42746.00 ns, 2.6090 ns/op
+OverheadActual 5: 16384 op, 41455.00 ns, 2.5302 ns/op
+OverheadActual 6: 16384 op, 41415.00 ns, 2.5278 ns/op
+OverheadActual 7: 16384 op, 46720.00 ns, 2.8516 ns/op
+OverheadActual 8: 16384 op, 42443.00 ns, 2.5905 ns/op
+OverheadActual 9: 16384 op, 41407.00 ns, 2.5273 ns/op
+OverheadActual 10: 16384 op, 57862.00 ns, 3.5316 ns/op
+OverheadActual 11: 16384 op, 41419.00 ns, 2.5280 ns/op
+OverheadActual 12: 16384 op, 42638.00 ns, 2.6024 ns/op
+OverheadActual 13: 16384 op, 41790.00 ns, 2.5507 ns/op
+OverheadActual 14: 16384 op, 41506.00 ns, 2.5333 ns/op
+OverheadActual 15: 16384 op, 41460.00 ns, 2.5305 ns/op
+
+WorkloadWarmup 1: 16384 op, 637750308.00 ns, 38.9252 us/op
+WorkloadWarmup 2: 16384 op, 626112726.00 ns, 38.2149 us/op
+WorkloadWarmup 3: 16384 op, 604989535.00 ns, 36.9256 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 16384 op, 603261148.00 ns, 36.8201 us/op
+WorkloadActual 2: 16384 op, 611720246.00 ns, 37.3364 us/op
+WorkloadActual 3: 16384 op, 621211501.00 ns, 37.9157 us/op
+
+// AfterActualRun
+WorkloadResult 1: 16384 op, 603219358.00 ns, 36.8176 us/op
+WorkloadResult 2: 16384 op, 611678456.00 ns, 37.3339 us/op
+WorkloadResult 3: 16384 op, 621169711.00 ns, 37.9132 us/op
+// GC: 42 0 0 730595328 16384
+// Threading: 0 0 16384
+
+// AfterAll
+// Benchmark Process 515301 has exited with code 0.
+
+Mean = 37.355 μs, StdErr = 0.316 μs (0.85%), N = 3, StdDev = 0.548 μs
+Min = 36.818 μs, Q1 = 37.076 μs, Median = 37.334 μs, Q3 = 37.624 μs, Max = 37.913 μs
+IQR = 0.548 μs, LowerFence = 36.254 μs, UpperFence = 38.445 μs
+ConfidenceInterval = [27.355 μs; 47.354 μs] (CI 99.9%), Margin = 9.999 μs (26.77% of Mean)
+Skewness = 0.04, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 9 (81.8 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 1m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan --job ShortRun --benchmarkId 2 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 241666.00 ns, 241.6660 us/op
+WorkloadJitting 1: 1 op, 3208072.00 ns, 3.2081 ms/op
+
+OverheadJitting 2: 16 op, 526185.00 ns, 32.8866 us/op
+WorkloadJitting 2: 16 op, 1652202.00 ns, 103.2626 us/op
+
+WorkloadPilot 1: 16 op, 1145985.00 ns, 71.6241 us/op
+WorkloadPilot 2: 32 op, 2301300.00 ns, 71.9156 us/op
+WorkloadPilot 3: 64 op, 4446958.00 ns, 69.4837 us/op
+WorkloadPilot 4: 128 op, 8704148.00 ns, 68.0012 us/op
+WorkloadPilot 5: 256 op, 17846111.00 ns, 69.7114 us/op
+WorkloadPilot 6: 512 op, 34894802.00 ns, 68.1539 us/op
+WorkloadPilot 7: 1024 op, 78848192.00 ns, 77.0002 us/op
+WorkloadPilot 8: 2048 op, 74904889.00 ns, 36.5747 us/op
+WorkloadPilot 9: 4096 op, 107074084.00 ns, 26.1411 us/op
+WorkloadPilot 10: 8192 op, 214815797.00 ns, 26.2226 us/op
+WorkloadPilot 11: 16384 op, 428579485.00 ns, 26.1584 us/op
+WorkloadPilot 12: 32768 op, 840009800.00 ns, 25.6351 us/op
+
+OverheadWarmup 1: 32768 op, 97059.00 ns, 2.9620 ns/op
+OverheadWarmup 2: 32768 op, 87728.00 ns, 2.6772 ns/op
+OverheadWarmup 3: 32768 op, 83195.00 ns, 2.5389 ns/op
+OverheadWarmup 4: 32768 op, 82314.00 ns, 2.5120 ns/op
+OverheadWarmup 5: 32768 op, 83314.00 ns, 2.5425 ns/op
+OverheadWarmup 6: 32768 op, 82398.00 ns, 2.5146 ns/op
+OverheadWarmup 7: 32768 op, 83138.00 ns, 2.5372 ns/op
+OverheadWarmup 8: 32768 op, 87057.00 ns, 2.6568 ns/op
+OverheadWarmup 9: 32768 op, 83394.00 ns, 2.5450 ns/op
+
+OverheadActual 1: 32768 op, 88453.00 ns, 2.6994 ns/op
+OverheadActual 2: 32768 op, 115169.00 ns, 3.5147 ns/op
+OverheadActual 3: 32768 op, 82766.00 ns, 2.5258 ns/op
+OverheadActual 4: 32768 op, 83352.00 ns, 2.5437 ns/op
+OverheadActual 5: 32768 op, 82546.00 ns, 2.5191 ns/op
+OverheadActual 6: 32768 op, 83276.00 ns, 2.5414 ns/op
+OverheadActual 7: 32768 op, 82390.00 ns, 2.5143 ns/op
+OverheadActual 8: 32768 op, 83228.00 ns, 2.5399 ns/op
+OverheadActual 9: 32768 op, 82401.00 ns, 2.5147 ns/op
+OverheadActual 10: 32768 op, 83199.00 ns, 2.5390 ns/op
+OverheadActual 11: 32768 op, 82489.00 ns, 2.5174 ns/op
+OverheadActual 12: 32768 op, 83204.00 ns, 2.5392 ns/op
+OverheadActual 13: 32768 op, 82331.00 ns, 2.5125 ns/op
+OverheadActual 14: 32768 op, 83281.00 ns, 2.5415 ns/op
+OverheadActual 15: 32768 op, 82389.00 ns, 2.5143 ns/op
+
+WorkloadWarmup 1: 32768 op, 847799032.00 ns, 25.8728 us/op
+WorkloadWarmup 2: 32768 op, 846953181.00 ns, 25.8470 us/op
+WorkloadWarmup 3: 32768 op, 847698978.00 ns, 25.8697 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 847825844.00 ns, 25.8736 us/op
+WorkloadActual 2: 32768 op, 846101636.00 ns, 25.8210 us/op
+WorkloadActual 3: 32768 op, 841086144.00 ns, 25.6679 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 847742645.00 ns, 25.8711 us/op
+WorkloadResult 2: 32768 op, 846018437.00 ns, 25.8184 us/op
+WorkloadResult 3: 32768 op, 841002945.00 ns, 25.6654 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 515486 has exited with code 0.
+
+Mean = 25.785 μs, StdErr = 0.062 μs (0.24%), N = 3, StdDev = 0.107 μs
+Min = 25.665 μs, Q1 = 25.742 μs, Median = 25.818 μs, Q3 = 25.845 μs, Max = 25.871 μs
+IQR = 0.103 μs, LowerFence = 25.588 μs, UpperFence = 25.999 μs
+ConfidenceInterval = [23.836 μs; 27.734 μs] (CI 99.9%), Margin = 1.949 μs (7.56% of Mean)
+Skewness = -0.28, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 8 (72.7 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck --job ShortRun --benchmarkId 3 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 238183.00 ns, 238.1830 us/op
+WorkloadJitting 1: 1 op, 3051883.00 ns, 3.0519 ms/op
+
+OverheadJitting 2: 16 op, 534348.00 ns, 33.3968 us/op
+WorkloadJitting 2: 16 op, 1624901.00 ns, 101.5563 us/op
+
+WorkloadPilot 1: 16 op, 1125462.00 ns, 70.3414 us/op
+WorkloadPilot 2: 32 op, 2246481.00 ns, 70.2025 us/op
+WorkloadPilot 3: 64 op, 4458665.00 ns, 69.6666 us/op
+WorkloadPilot 4: 128 op, 8810577.00 ns, 68.8326 us/op
+WorkloadPilot 5: 256 op, 17244580.00 ns, 67.3616 us/op
+WorkloadPilot 6: 512 op, 34077336.00 ns, 66.5573 us/op
+WorkloadPilot 7: 1024 op, 73525944.00 ns, 71.8027 us/op
+WorkloadPilot 8: 2048 op, 77263273.00 ns, 37.7262 us/op
+WorkloadPilot 9: 4096 op, 108841018.00 ns, 26.5725 us/op
+WorkloadPilot 10: 8192 op, 218922321.00 ns, 26.7239 us/op
+WorkloadPilot 11: 16384 op, 446649091.00 ns, 27.2613 us/op
+WorkloadPilot 12: 32768 op, 869738211.00 ns, 26.5423 us/op
+
+OverheadWarmup 1: 32768 op, 84235.00 ns, 2.5706 ns/op
+OverheadWarmup 2: 32768 op, 91499.00 ns, 2.7923 ns/op
+OverheadWarmup 3: 32768 op, 82756.00 ns, 2.5255 ns/op
+OverheadWarmup 4: 32768 op, 81737.00 ns, 2.4944 ns/op
+OverheadWarmup 5: 32768 op, 95769.00 ns, 2.9226 ns/op
+OverheadWarmup 6: 32768 op, 81735.00 ns, 2.4944 ns/op
+
+OverheadActual 1: 32768 op, 83492.00 ns, 2.5480 ns/op
+OverheadActual 2: 32768 op, 82094.00 ns, 2.5053 ns/op
+OverheadActual 3: 32768 op, 83285.00 ns, 2.5417 ns/op
+OverheadActual 4: 32768 op, 81941.00 ns, 2.5006 ns/op
+OverheadActual 5: 32768 op, 82992.00 ns, 2.5327 ns/op
+OverheadActual 6: 32768 op, 81744.00 ns, 2.4946 ns/op
+OverheadActual 7: 32768 op, 82587.00 ns, 2.5204 ns/op
+OverheadActual 8: 32768 op, 81636.00 ns, 2.4913 ns/op
+OverheadActual 9: 32768 op, 82801.00 ns, 2.5269 ns/op
+OverheadActual 10: 32768 op, 81665.00 ns, 2.4922 ns/op
+OverheadActual 11: 32768 op, 82464.00 ns, 2.5166 ns/op
+OverheadActual 12: 32768 op, 81863.00 ns, 2.4983 ns/op
+OverheadActual 13: 32768 op, 82630.00 ns, 2.5217 ns/op
+OverheadActual 14: 32768 op, 81655.00 ns, 2.4919 ns/op
+OverheadActual 15: 32768 op, 86713.00 ns, 2.6463 ns/op
+
+WorkloadWarmup 1: 32768 op, 873005425.00 ns, 26.6420 us/op
+WorkloadWarmup 2: 32768 op, 876081572.00 ns, 26.7359 us/op
+WorkloadWarmup 3: 32768 op, 859007228.00 ns, 26.2148 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 858132124.00 ns, 26.1881 us/op
+WorkloadActual 2: 32768 op, 870316576.00 ns, 26.5600 us/op
+WorkloadActual 3: 32768 op, 871136513.00 ns, 26.5850 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 858049660.00 ns, 26.1856 us/op
+WorkloadResult 2: 32768 op, 870234112.00 ns, 26.5574 us/op
+WorkloadResult 3: 32768 op, 871054049.00 ns, 26.5825 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 515694 has exited with code 0.
+
+Mean = 26.442 μs, StdErr = 0.128 μs (0.49%), N = 3, StdDev = 0.222 μs
+Min = 26.186 μs, Q1 = 26.372 μs, Median = 26.557 μs, Q3 = 26.570 μs, Max = 26.582 μs
+IQR = 0.198 μs, LowerFence = 26.074 μs, UpperFence = 26.868 μs
+ConfidenceInterval = [22.387 μs; 30.497 μs] (CI 99.9%), Margin = 4.055 μs (15.33% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 7 (63.6 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck --job ShortRun --benchmarkId 4 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 288201.00 ns, 288.2010 us/op
+WorkloadJitting 1: 1 op, 3021136.00 ns, 3.0211 ms/op
+
+OverheadJitting 2: 16 op, 521220.00 ns, 32.5763 us/op
+WorkloadJitting 2: 16 op, 1707358.00 ns, 106.7099 us/op
+
+WorkloadPilot 1: 16 op, 1159466.00 ns, 72.4666 us/op
+WorkloadPilot 2: 32 op, 2261575.00 ns, 70.6742 us/op
+WorkloadPilot 3: 64 op, 4578178.00 ns, 71.5340 us/op
+WorkloadPilot 4: 128 op, 8833907.00 ns, 69.0149 us/op
+WorkloadPilot 5: 256 op, 17431143.00 ns, 68.0904 us/op
+WorkloadPilot 6: 512 op, 34799752.00 ns, 67.9683 us/op
+WorkloadPilot 7: 1024 op, 93118711.00 ns, 90.9362 us/op
+WorkloadPilot 8: 2048 op, 77946007.00 ns, 38.0596 us/op
+WorkloadPilot 9: 4096 op, 108559129.00 ns, 26.5037 us/op
+WorkloadPilot 10: 8192 op, 212368593.00 ns, 25.9239 us/op
+WorkloadPilot 11: 16384 op, 429450971.00 ns, 26.2116 us/op
+WorkloadPilot 12: 32768 op, 849973192.00 ns, 25.9391 us/op
+
+OverheadWarmup 1: 32768 op, 84381.00 ns, 2.5751 ns/op
+OverheadWarmup 2: 32768 op, 82070.00 ns, 2.5046 ns/op
+OverheadWarmup 3: 32768 op, 85460.00 ns, 2.6080 ns/op
+OverheadWarmup 4: 32768 op, 81786.00 ns, 2.4959 ns/op
+OverheadWarmup 5: 32768 op, 82773.00 ns, 2.5260 ns/op
+OverheadWarmup 6: 32768 op, 81907.00 ns, 2.4996 ns/op
+
+OverheadActual 1: 32768 op, 83126.00 ns, 2.5368 ns/op
+OverheadActual 2: 32768 op, 82134.00 ns, 2.5065 ns/op
+OverheadActual 3: 32768 op, 84982.00 ns, 2.5934 ns/op
+OverheadActual 4: 32768 op, 81909.00 ns, 2.4997 ns/op
+OverheadActual 5: 32768 op, 82895.00 ns, 2.5298 ns/op
+OverheadActual 6: 32768 op, 81929.00 ns, 2.5003 ns/op
+OverheadActual 7: 32768 op, 82782.00 ns, 2.5263 ns/op
+OverheadActual 8: 32768 op, 81812.00 ns, 2.4967 ns/op
+OverheadActual 9: 32768 op, 82483.00 ns, 2.5172 ns/op
+OverheadActual 10: 32768 op, 81911.00 ns, 2.4997 ns/op
+OverheadActual 11: 32768 op, 95321.00 ns, 2.9090 ns/op
+OverheadActual 12: 32768 op, 81819.00 ns, 2.4969 ns/op
+OverheadActual 13: 32768 op, 82662.00 ns, 2.5226 ns/op
+OverheadActual 14: 32768 op, 96959.00 ns, 2.9590 ns/op
+OverheadActual 15: 32768 op, 87395.00 ns, 2.6671 ns/op
+
+WorkloadWarmup 1: 32768 op, 861314896.00 ns, 26.2852 us/op
+WorkloadWarmup 2: 32768 op, 873045879.00 ns, 26.6432 us/op
+WorkloadWarmup 3: 32768 op, 851064812.00 ns, 25.9724 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 32768 op, 856095204.00 ns, 26.1260 us/op
+WorkloadActual 2: 32768 op, 842816514.00 ns, 25.7207 us/op
+WorkloadActual 3: 32768 op, 839734240.00 ns, 25.6267 us/op
+
+// AfterActualRun
+WorkloadResult 1: 32768 op, 856012542.00 ns, 26.1234 us/op
+WorkloadResult 2: 32768 op, 842733852.00 ns, 25.7182 us/op
+WorkloadResult 3: 32768 op, 839651578.00 ns, 25.6241 us/op
+// GC: 32 0 0 561250304 32768
+// Threading: 0 0 32768
+
+// AfterAll
+// Benchmark Process 515972 has exited with code 0.
+
+Mean = 25.822 μs, StdErr = 0.153 μs (0.59%), N = 3, StdDev = 0.265 μs
+Min = 25.624 μs, Q1 = 25.671 μs, Median = 25.718 μs, Q3 = 25.921 μs, Max = 26.123 μs
+IQR = 0.250 μs, LowerFence = 25.297 μs, UpperFence = 26.295 μs
+ConfidenceInterval = [20.982 μs; 30.662 μs] (CI 99.9%), Margin = 4.840 μs (18.75% of Mean)
+Skewness = 0.33, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 6 (54.5 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripWhitespace_Benchmark --job ShortRun --benchmarkId 5 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 249189.00 ns, 249.1890 us/op
+WorkloadJitting 1: 1 op, 15597450.00 ns, 15.5975 ms/op
+
+OverheadJitting 2: 16 op, 646694.00 ns, 40.4184 us/op
+WorkloadJitting 2: 16 op, 794887.00 ns, 49.6804 us/op
+
+WorkloadPilot 1: 16 op, 28513.00 ns, 1.7821 us/op
+WorkloadPilot 2: 32 op, 39116.00 ns, 1.2224 us/op
+WorkloadPilot 3: 64 op, 96170.00 ns, 1.5027 us/op
+WorkloadPilot 4: 128 op, 121146.00 ns, 946.4531 ns/op
+WorkloadPilot 5: 256 op, 260126.00 ns, 1.0161 us/op
+WorkloadPilot 6: 512 op, 444210.00 ns, 867.5977 ns/op
+WorkloadPilot 7: 1024 op, 858824.00 ns, 838.6953 ns/op
+WorkloadPilot 8: 2048 op, 1710931.00 ns, 835.4155 ns/op
+WorkloadPilot 9: 4096 op, 3351226.00 ns, 818.1704 ns/op
+WorkloadPilot 10: 8192 op, 6901018.00 ns, 842.4094 ns/op
+WorkloadPilot 11: 16384 op, 13439478.00 ns, 820.2806 ns/op
+WorkloadPilot 12: 32768 op, 26486716.00 ns, 808.3104 ns/op
+WorkloadPilot 13: 65536 op, 52238242.00 ns, 797.0923 ns/op
+WorkloadPilot 14: 131072 op, 73883976.00 ns, 563.6900 ns/op
+WorkloadPilot 15: 262144 op, 78390103.00 ns, 299.0345 ns/op
+WorkloadPilot 16: 524288 op, 146677070.00 ns, 279.7643 ns/op
+WorkloadPilot 17: 1048576 op, 290206297.00 ns, 276.7623 ns/op
+WorkloadPilot 18: 2097152 op, 572540033.00 ns, 273.0084 ns/op
+
+OverheadWarmup 1: 2097152 op, 9303166.00 ns, 4.4361 ns/op
+OverheadWarmup 2: 2097152 op, 9351402.00 ns, 4.4591 ns/op
+OverheadWarmup 3: 2097152 op, 9307356.00 ns, 4.4381 ns/op
+OverheadWarmup 4: 2097152 op, 9272798.00 ns, 4.4216 ns/op
+OverheadWarmup 5: 2097152 op, 9283571.00 ns, 4.4268 ns/op
+OverheadWarmup 6: 2097152 op, 9290745.00 ns, 4.4302 ns/op
+OverheadWarmup 7: 2097152 op, 9289424.00 ns, 4.4295 ns/op
+
+OverheadActual 1: 2097152 op, 9241341.00 ns, 4.4066 ns/op
+OverheadActual 2: 2097152 op, 9262750.00 ns, 4.4168 ns/op
+OverheadActual 3: 2097152 op, 9308971.00 ns, 4.4389 ns/op
+OverheadActual 4: 2097152 op, 9301890.00 ns, 4.4355 ns/op
+OverheadActual 5: 2097152 op, 9261906.00 ns, 4.4164 ns/op
+OverheadActual 6: 2097152 op, 9308235.00 ns, 4.4385 ns/op
+OverheadActual 7: 2097152 op, 9311710.00 ns, 4.4402 ns/op
+OverheadActual 8: 2097152 op, 9269231.00 ns, 4.4199 ns/op
+OverheadActual 9: 2097152 op, 9314965.00 ns, 4.4417 ns/op
+OverheadActual 10: 2097152 op, 9311108.00 ns, 4.4399 ns/op
+OverheadActual 11: 2097152 op, 9263448.00 ns, 4.4172 ns/op
+OverheadActual 12: 2097152 op, 9281033.00 ns, 4.4255 ns/op
+OverheadActual 13: 2097152 op, 9270577.00 ns, 4.4206 ns/op
+OverheadActual 14: 2097152 op, 9305244.00 ns, 4.4371 ns/op
+OverheadActual 15: 2097152 op, 9293349.00 ns, 4.4314 ns/op
+
+WorkloadWarmup 1: 2097152 op, 602061695.00 ns, 287.0854 ns/op
+WorkloadWarmup 2: 2097152 op, 575196708.00 ns, 274.2752 ns/op
+WorkloadWarmup 3: 2097152 op, 567713355.00 ns, 270.7068 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 2097152 op, 571008361.00 ns, 272.2780 ns/op
+WorkloadActual 2: 2097152 op, 570541089.00 ns, 272.0552 ns/op
+WorkloadActual 3: 2097152 op, 580043290.00 ns, 276.5862 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 2097152 op, 561715012.00 ns, 267.8466 ns/op
+WorkloadResult 2: 2097152 op, 561247740.00 ns, 267.6238 ns/op
+WorkloadResult 3: 2097152 op, 570749941.00 ns, 272.1548 ns/op
+// GC: 7 0 0 134218560 2097152
+// Threading: 0 0 2097152
+
+// AfterAll
+// Benchmark Process 516218 has exited with code 0.
+
+Mean = 269.208 ns, StdErr = 1.475 ns (0.55%), N = 3, StdDev = 2.554 ns
+Min = 267.624 ns, Q1 = 267.735 ns, Median = 267.847 ns, Q3 = 270.001 ns, Max = 272.155 ns
+IQR = 2.266 ns, LowerFence = 264.337 ns, UpperFence = 273.399 ns
+ConfidenceInterval = [222.612 ns; 315.804 ns] (CI 99.9%), Margin = 46.596 ns (17.31% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 5 (45.5 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.GetFileExtension_Benchmark --job ShortRun --benchmarkId 6 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 248866.00 ns, 248.8660 us/op
+WorkloadJitting 1: 1 op, 16648495.00 ns, 16.6485 ms/op
+
+OverheadJitting 2: 16 op, 663308.00 ns, 41.4568 us/op
+WorkloadJitting 2: 16 op, 676417.00 ns, 42.2761 us/op
+
+WorkloadPilot 1: 16 op, 33056.00 ns, 2.0660 us/op
+WorkloadPilot 2: 32 op, 46741.00 ns, 1.4607 us/op
+WorkloadPilot 3: 64 op, 55273.00 ns, 863.6406 ns/op
+WorkloadPilot 4: 128 op, 121249.00 ns, 947.2578 ns/op
+WorkloadPilot 5: 256 op, 203737.00 ns, 795.8477 ns/op
+WorkloadPilot 6: 512 op, 291040.00 ns, 568.4375 ns/op
+WorkloadPilot 7: 1024 op, 687656.00 ns, 671.5391 ns/op
+WorkloadPilot 8: 2048 op, 1285534.00 ns, 627.7021 ns/op
+WorkloadPilot 9: 4096 op, 2694354.00 ns, 657.8013 ns/op
+WorkloadPilot 10: 8192 op, 5125355.00 ns, 625.6537 ns/op
+WorkloadPilot 11: 16384 op, 10272709.00 ns, 626.9964 ns/op
+WorkloadPilot 12: 32768 op, 20105186.00 ns, 613.5616 ns/op
+WorkloadPilot 13: 65536 op, 28264051.00 ns, 431.2752 ns/op
+WorkloadPilot 14: 131072 op, 69704472.00 ns, 531.8029 ns/op
+WorkloadPilot 15: 262144 op, 94231517.00 ns, 359.4647 ns/op
+WorkloadPilot 16: 524288 op, 165708145.00 ns, 316.0632 ns/op
+WorkloadPilot 17: 1048576 op, 332009328.00 ns, 316.6288 ns/op
+WorkloadPilot 18: 2097152 op, 650295645.00 ns, 310.0851 ns/op
+
+OverheadWarmup 1: 2097152 op, 10083108.00 ns, 4.8080 ns/op
+OverheadWarmup 2: 2097152 op, 10113440.00 ns, 4.8225 ns/op
+OverheadWarmup 3: 2097152 op, 10070849.00 ns, 4.8022 ns/op
+OverheadWarmup 4: 2097152 op, 10084275.00 ns, 4.8086 ns/op
+OverheadWarmup 5: 2097152 op, 10135269.00 ns, 4.8329 ns/op
+OverheadWarmup 6: 2097152 op, 10081887.00 ns, 4.8074 ns/op
+
+OverheadActual 1: 2097152 op, 10085754.00 ns, 4.8093 ns/op
+OverheadActual 2: 2097152 op, 10144350.00 ns, 4.8372 ns/op
+OverheadActual 3: 2097152 op, 10086436.00 ns, 4.8096 ns/op
+OverheadActual 4: 2097152 op, 10103800.00 ns, 4.8179 ns/op
+OverheadActual 5: 2097152 op, 10104139.00 ns, 4.8180 ns/op
+OverheadActual 6: 2097152 op, 10119890.00 ns, 4.8255 ns/op
+OverheadActual 7: 2097152 op, 10099932.00 ns, 4.8160 ns/op
+OverheadActual 8: 2097152 op, 10087533.00 ns, 4.8101 ns/op
+OverheadActual 9: 2097152 op, 10098295.00 ns, 4.8152 ns/op
+OverheadActual 10: 2097152 op, 10061202.00 ns, 4.7976 ns/op
+OverheadActual 11: 2097152 op, 10059229.00 ns, 4.7966 ns/op
+OverheadActual 12: 2097152 op, 10113674.00 ns, 4.8226 ns/op
+OverheadActual 13: 2097152 op, 10097273.00 ns, 4.8148 ns/op
+OverheadActual 14: 2097152 op, 10071570.00 ns, 4.8025 ns/op
+OverheadActual 15: 2097152 op, 10086921.00 ns, 4.8098 ns/op
+
+WorkloadWarmup 1: 2097152 op, 646086542.00 ns, 308.0781 ns/op
+WorkloadWarmup 2: 2097152 op, 642786786.00 ns, 306.5046 ns/op
+WorkloadWarmup 3: 2097152 op, 662013215.00 ns, 315.6725 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 2097152 op, 668839336.00 ns, 318.9274 ns/op
+WorkloadActual 2: 2097152 op, 645810836.00 ns, 307.9466 ns/op
+WorkloadActual 3: 2097152 op, 659588216.00 ns, 314.5162 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 2097152 op, 658742063.00 ns, 314.1127 ns/op
+WorkloadResult 2: 2097152 op, 635713563.00 ns, 303.1318 ns/op
+WorkloadResult 3: 2097152 op, 649490943.00 ns, 309.7014 ns/op
+// GC: 67 0 0 1157627904 2097152
+// Threading: 0 0 2097152
+
+// AfterAll
+// Benchmark Process 516401 has exited with code 0.
+
+Mean = 308.982 ns, StdErr = 3.190 ns (1.03%), N = 3, StdDev = 5.526 ns
+Min = 303.132 ns, Q1 = 306.417 ns, Median = 309.701 ns, Q3 = 311.907 ns, Max = 314.113 ns
+IQR = 5.490 ns, LowerFence = 298.181 ns, UpperFence = 320.143 ns
+ConfidenceInterval = [208.173 ns; 409.791 ns] (CI 99.9%), Margin = 100.809 ns (32.63% of Mean)
+Skewness = -0.13, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 4 (36.4 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.StripHtml_Benchmark --job ShortRun --benchmarkId 7 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 263065.00 ns, 263.0650 us/op
+WorkloadJitting 1: 1 op, 18054579.00 ns, 18.0546 ms/op
+
+OverheadJitting 2: 16 op, 780382.00 ns, 48.7739 us/op
+WorkloadJitting 2: 16 op, 938144.00 ns, 58.6340 us/op
+
+WorkloadPilot 1: 16 op, 53906.00 ns, 3.3691 us/op
+WorkloadPilot 2: 32 op, 97013.00 ns, 3.0317 us/op
+WorkloadPilot 3: 64 op, 153167.00 ns, 2.3932 us/op
+WorkloadPilot 4: 128 op, 213824.00 ns, 1.6705 us/op
+WorkloadPilot 5: 256 op, 402407.00 ns, 1.5719 us/op
+WorkloadPilot 6: 512 op, 741786.00 ns, 1.4488 us/op
+WorkloadPilot 7: 1024 op, 1435157.00 ns, 1.4015 us/op
+WorkloadPilot 8: 2048 op, 2872197.00 ns, 1.4024 us/op
+WorkloadPilot 9: 4096 op, 5965787.00 ns, 1.4565 us/op
+WorkloadPilot 10: 8192 op, 11985638.00 ns, 1.4631 us/op
+WorkloadPilot 11: 16384 op, 22052793.00 ns, 1.3460 us/op
+WorkloadPilot 12: 32768 op, 43717363.00 ns, 1.3341 us/op
+WorkloadPilot 13: 65536 op, 80014512.00 ns, 1.2209 us/op
+WorkloadPilot 14: 131072 op, 96130644.00 ns, 733.4186 ns/op
+WorkloadPilot 15: 262144 op, 193036303.00 ns, 736.3751 ns/op
+WorkloadPilot 16: 524288 op, 380950366.00 ns, 726.6052 ns/op
+WorkloadPilot 17: 1048576 op, 749461148.00 ns, 714.7418 ns/op
+
+OverheadWarmup 1: 1048576 op, 4678883.00 ns, 4.4621 ns/op
+OverheadWarmup 2: 1048576 op, 4665293.00 ns, 4.4492 ns/op
+OverheadWarmup 3: 1048576 op, 4693863.00 ns, 4.4764 ns/op
+OverheadWarmup 4: 1048576 op, 4661668.00 ns, 4.4457 ns/op
+OverheadWarmup 5: 1048576 op, 4660549.00 ns, 4.4446 ns/op
+OverheadWarmup 6: 1048576 op, 4667935.00 ns, 4.4517 ns/op
+OverheadWarmup 7: 1048576 op, 4662647.00 ns, 4.4466 ns/op
+
+OverheadActual 1: 1048576 op, 4667319.00 ns, 4.4511 ns/op
+OverheadActual 2: 1048576 op, 4678832.00 ns, 4.4621 ns/op
+OverheadActual 3: 1048576 op, 4705640.00 ns, 4.4876 ns/op
+OverheadActual 4: 1048576 op, 4663745.00 ns, 4.4477 ns/op
+OverheadActual 5: 1048576 op, 4676329.00 ns, 4.4597 ns/op
+OverheadActual 6: 1048576 op, 4661213.00 ns, 4.4453 ns/op
+OverheadActual 7: 1048576 op, 4672441.00 ns, 4.4560 ns/op
+OverheadActual 8: 1048576 op, 4680925.00 ns, 4.4641 ns/op
+OverheadActual 9: 1048576 op, 4644836.00 ns, 4.4297 ns/op
+OverheadActual 10: 1048576 op, 4676148.00 ns, 4.4595 ns/op
+OverheadActual 11: 1048576 op, 4666167.00 ns, 4.4500 ns/op
+OverheadActual 12: 1048576 op, 4653982.00 ns, 4.4384 ns/op
+OverheadActual 13: 1048576 op, 4652265.00 ns, 4.4367 ns/op
+OverheadActual 14: 1048576 op, 4688391.00 ns, 4.4712 ns/op
+OverheadActual 15: 1048576 op, 4677674.00 ns, 4.4610 ns/op
+
+WorkloadWarmup 1: 1048576 op, 772819750.00 ns, 737.0183 ns/op
+WorkloadWarmup 2: 1048576 op, 770846937.00 ns, 735.1369 ns/op
+WorkloadWarmup 3: 1048576 op, 769209986.00 ns, 733.5758 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 1048576 op, 770315816.00 ns, 734.6304 ns/op
+WorkloadActual 2: 1048576 op, 758187039.00 ns, 723.0635 ns/op
+WorkloadActual 3: 1048576 op, 749428108.00 ns, 714.7103 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 1048576 op, 765643375.00 ns, 730.1744 ns/op
+WorkloadResult 2: 1048576 op, 753514598.00 ns, 718.6075 ns/op
+WorkloadResult 3: 1048576 op, 744755667.00 ns, 710.2544 ns/op
+// GC: 2 0 0 50331960 1048576
+// Threading: 0 0 1048576
+
+// AfterAll
+// Benchmark Process 516590 has exited with code 0.
+
+Mean = 719.679 ns, StdErr = 5.775 ns (0.80%), N = 3, StdDev = 10.003 ns
+Min = 710.254 ns, Q1 = 714.431 ns, Median = 718.608 ns, Q3 = 724.391 ns, Max = 730.174 ns
+IQR = 9.960 ns, LowerFence = 699.491 ns, UpperFence = 739.331 ns
+ConfidenceInterval = [537.184 ns; 902.173 ns] (CI 99.9%), Margin = 182.495 ns (25.36% of Mean)
+Skewness = 0.11, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 3 (27.3 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsLowerCase_Benchmark --job ShortRun --benchmarkId 8 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 250041.00 ns, 250.0410 us/op
+WorkloadJitting 1: 1 op, 4014650.00 ns, 4.0147 ms/op
+
+OverheadJitting 2: 16 op, 509480.00 ns, 31.8425 us/op
+WorkloadJitting 2: 16 op, 476824.00 ns, 29.8015 us/op
+
+WorkloadPilot 1: 16 op, 1488.00 ns, 93.0000 ns/op
+WorkloadPilot 2: 32 op, 1157.00 ns, 36.1563 ns/op
+WorkloadPilot 3: 64 op, 1123.00 ns, 17.5469 ns/op
+WorkloadPilot 4: 128 op, 1523.00 ns, 11.8984 ns/op
+WorkloadPilot 5: 256 op, 3617.00 ns, 14.1289 ns/op
+WorkloadPilot 6: 512 op, 4192.00 ns, 8.1875 ns/op
+WorkloadPilot 7: 1024 op, 7405.00 ns, 7.2314 ns/op
+WorkloadPilot 8: 2048 op, 14116.00 ns, 6.8926 ns/op
+WorkloadPilot 9: 4096 op, 27743.00 ns, 6.7732 ns/op
+WorkloadPilot 10: 8192 op, 55986.00 ns, 6.8342 ns/op
+WorkloadPilot 11: 16384 op, 108741.00 ns, 6.6370 ns/op
+WorkloadPilot 12: 32768 op, 216875.00 ns, 6.6185 ns/op
+WorkloadPilot 13: 65536 op, 437620.00 ns, 6.6776 ns/op
+WorkloadPilot 14: 131072 op, 887839.00 ns, 6.7737 ns/op
+WorkloadPilot 15: 262144 op, 1779224.00 ns, 6.7872 ns/op
+WorkloadPilot 16: 524288 op, 3512284.00 ns, 6.6992 ns/op
+WorkloadPilot 17: 1048576 op, 7315397.00 ns, 6.9765 ns/op
+WorkloadPilot 18: 2097152 op, 14227266.00 ns, 6.7841 ns/op
+WorkloadPilot 19: 4194304 op, 28263272.00 ns, 6.7385 ns/op
+WorkloadPilot 20: 8388608 op, 59140400.00 ns, 7.0501 ns/op
+WorkloadPilot 21: 16777216 op, 32691512.00 ns, 1.9486 ns/op
+WorkloadPilot 22: 33554432 op, 65417248.00 ns, 1.9496 ns/op
+WorkloadPilot 23: 67108864 op, 130644133.00 ns, 1.9467 ns/op
+WorkloadPilot 24: 134217728 op, 261933255.00 ns, 1.9516 ns/op
+WorkloadPilot 25: 268435456 op, 523334920.00 ns, 1.9496 ns/op
+
+OverheadWarmup 1: 268435456 op, 572226994.00 ns, 2.1317 ns/op
+OverheadWarmup 2: 268435456 op, 521748699.00 ns, 1.9437 ns/op
+OverheadWarmup 3: 268435456 op, 520603385.00 ns, 1.9394 ns/op
+OverheadWarmup 4: 268435456 op, 514829546.00 ns, 1.9179 ns/op
+OverheadWarmup 5: 268435456 op, 515629496.00 ns, 1.9209 ns/op
+OverheadWarmup 6: 268435456 op, 520380002.00 ns, 1.9386 ns/op
+OverheadWarmup 7: 268435456 op, 522823039.00 ns, 1.9477 ns/op
+OverheadWarmup 8: 268435456 op, 521145137.00 ns, 1.9414 ns/op
+OverheadWarmup 9: 268435456 op, 515237018.00 ns, 1.9194 ns/op
+OverheadWarmup 10: 268435456 op, 516079080.00 ns, 1.9225 ns/op
+
+OverheadActual 1: 268435456 op, 514531072.00 ns, 1.9168 ns/op
+OverheadActual 2: 268435456 op, 514143417.00 ns, 1.9153 ns/op
+OverheadActual 3: 268435456 op, 516770627.00 ns, 1.9251 ns/op
+OverheadActual 4: 268435456 op, 515748059.00 ns, 1.9213 ns/op
+OverheadActual 5: 268435456 op, 515804459.00 ns, 1.9215 ns/op
+OverheadActual 6: 268435456 op, 515436128.00 ns, 1.9201 ns/op
+OverheadActual 7: 268435456 op, 518310694.00 ns, 1.9309 ns/op
+OverheadActual 8: 268435456 op, 517742027.00 ns, 1.9287 ns/op
+OverheadActual 9: 268435456 op, 516181663.00 ns, 1.9229 ns/op
+OverheadActual 10: 268435456 op, 515650621.00 ns, 1.9209 ns/op
+OverheadActual 11: 268435456 op, 515798670.00 ns, 1.9215 ns/op
+OverheadActual 12: 268435456 op, 514377358.00 ns, 1.9162 ns/op
+OverheadActual 13: 268435456 op, 515994838.00 ns, 1.9222 ns/op
+OverheadActual 14: 268435456 op, 514817499.00 ns, 1.9178 ns/op
+OverheadActual 15: 268435456 op, 514370770.00 ns, 1.9162 ns/op
+
+WorkloadWarmup 1: 268435456 op, 514015051.00 ns, 1.9149 ns/op
+WorkloadWarmup 2: 268435456 op, 532966366.00 ns, 1.9855 ns/op
+WorkloadWarmup 3: 268435456 op, 521544842.00 ns, 1.9429 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 268435456 op, 523663141.00 ns, 1.9508 ns/op
+WorkloadActual 2: 268435456 op, 521604576.00 ns, 1.9431 ns/op
+WorkloadActual 3: 268435456 op, 517581583.00 ns, 1.9281 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 268435456 op, 7915082.00 ns, 0.0295 ns/op
+WorkloadResult 2: 268435456 op, 5856517.00 ns, 0.0218 ns/op
+WorkloadResult 3: 268435456 op, 1833524.00 ns, 0.0068 ns/op
+// GC: 0 0 0 0 268435456
+// Threading: 0 0 268435456
+
+// AfterAll
+// Benchmark Process 516779 has exited with code 0.
+
+Mean = 0.019 ns, StdErr = 0.007 ns (34.33%), N = 3, StdDev = 0.012 ns
+Min = 0.007 ns, Q1 = 0.014 ns, Median = 0.022 ns, Q3 = 0.026 ns, Max = 0.029 ns
+IQR = 0.011 ns, LowerFence = -0.003 ns, UpperFence = 0.043 ns
+ConfidenceInterval = [-0.191 ns; 0.230 ns] (CI 99.9%), Margin = 0.210 ns (1084.87% of Mean)
+Skewness = -0.2, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 2 (18.2 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.IsUpperCase_Benchmark --job ShortRun --benchmarkId 9 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 321822.00 ns, 321.8220 us/op
+WorkloadJitting 1: 1 op, 3627803.00 ns, 3.6278 ms/op
+
+OverheadJitting 2: 16 op, 505989.00 ns, 31.6243 us/op
+WorkloadJitting 2: 16 op, 500173.00 ns, 31.2608 us/op
+
+WorkloadPilot 1: 16 op, 1885.00 ns, 117.8125 ns/op
+WorkloadPilot 2: 32 op, 1314.00 ns, 41.0625 ns/op
+WorkloadPilot 3: 64 op, 1758.00 ns, 27.4688 ns/op
+WorkloadPilot 4: 128 op, 1682.00 ns, 13.1406 ns/op
+WorkloadPilot 5: 256 op, 2223.00 ns, 8.6836 ns/op
+WorkloadPilot 6: 512 op, 4034.00 ns, 7.8789 ns/op
+WorkloadPilot 7: 1024 op, 7262.00 ns, 7.0918 ns/op
+WorkloadPilot 8: 2048 op, 14047.00 ns, 6.8589 ns/op
+WorkloadPilot 9: 4096 op, 39698.00 ns, 9.6919 ns/op
+WorkloadPilot 10: 8192 op, 54704.00 ns, 6.6777 ns/op
+WorkloadPilot 11: 16384 op, 108740.00 ns, 6.6370 ns/op
+WorkloadPilot 12: 32768 op, 235630.00 ns, 7.1909 ns/op
+WorkloadPilot 13: 65536 op, 464078.00 ns, 7.0813 ns/op
+WorkloadPilot 14: 131072 op, 882880.00 ns, 6.7358 ns/op
+WorkloadPilot 15: 262144 op, 1780084.00 ns, 6.7905 ns/op
+WorkloadPilot 16: 524288 op, 3521222.00 ns, 6.7162 ns/op
+WorkloadPilot 17: 1048576 op, 7103812.00 ns, 6.7747 ns/op
+WorkloadPilot 18: 2097152 op, 14091859.00 ns, 6.7195 ns/op
+WorkloadPilot 19: 4194304 op, 28401041.00 ns, 6.7713 ns/op
+WorkloadPilot 20: 8388608 op, 47707706.00 ns, 5.6872 ns/op
+WorkloadPilot 21: 16777216 op, 32616382.00 ns, 1.9441 ns/op
+WorkloadPilot 22: 33554432 op, 65638730.00 ns, 1.9562 ns/op
+WorkloadPilot 23: 67108864 op, 130613784.00 ns, 1.9463 ns/op
+WorkloadPilot 24: 134217728 op, 261427515.00 ns, 1.9478 ns/op
+WorkloadPilot 25: 268435456 op, 522228724.00 ns, 1.9455 ns/op
+
+OverheadWarmup 1: 268435456 op, 570458086.00 ns, 2.1251 ns/op
+OverheadWarmup 2: 268435456 op, 521466899.00 ns, 1.9426 ns/op
+OverheadWarmup 3: 268435456 op, 523628719.00 ns, 1.9507 ns/op
+OverheadWarmup 4: 268435456 op, 515871142.00 ns, 1.9218 ns/op
+OverheadWarmup 5: 268435456 op, 514608481.00 ns, 1.9171 ns/op
+OverheadWarmup 6: 268435456 op, 516735500.00 ns, 1.9250 ns/op
+OverheadWarmup 7: 268435456 op, 515108210.00 ns, 1.9189 ns/op
+
+OverheadActual 1: 268435456 op, 534298129.00 ns, 1.9904 ns/op
+OverheadActual 2: 268435456 op, 520834761.00 ns, 1.9403 ns/op
+OverheadActual 3: 268435456 op, 521953769.00 ns, 1.9444 ns/op
+OverheadActual 4: 268435456 op, 521892009.00 ns, 1.9442 ns/op
+OverheadActual 5: 268435456 op, 522693727.00 ns, 1.9472 ns/op
+OverheadActual 6: 268435456 op, 521541831.00 ns, 1.9429 ns/op
+OverheadActual 7: 268435456 op, 518271350.00 ns, 1.9307 ns/op
+OverheadActual 8: 268435456 op, 514201569.00 ns, 1.9156 ns/op
+OverheadActual 9: 268435456 op, 526556509.00 ns, 1.9616 ns/op
+OverheadActual 10: 268435456 op, 524017656.00 ns, 1.9521 ns/op
+OverheadActual 11: 268435456 op, 532883072.00 ns, 1.9851 ns/op
+OverheadActual 12: 268435456 op, 513863230.00 ns, 1.9143 ns/op
+OverheadActual 13: 268435456 op, 514866887.00 ns, 1.9180 ns/op
+OverheadActual 14: 268435456 op, 516378020.00 ns, 1.9237 ns/op
+OverheadActual 15: 268435456 op, 515184242.00 ns, 1.9192 ns/op
+
+WorkloadWarmup 1: 268435456 op, 515542011.00 ns, 1.9205 ns/op
+WorkloadWarmup 2: 268435456 op, 515168857.00 ns, 1.9192 ns/op
+WorkloadWarmup 3: 268435456 op, 515031138.00 ns, 1.9186 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 268435456 op, 515839280.00 ns, 1.9217 ns/op
+WorkloadActual 2: 268435456 op, 521472494.00 ns, 1.9426 ns/op
+WorkloadActual 3: 268435456 op, 527812729.00 ns, 1.9663 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 268435456 op, 0.00 ns, 0.0000 ns/op
+WorkloadResult 2: 268435456 op, 0.00 ns, 0.0000 ns/op
+WorkloadResult 3: 268435456 op, 6270898.00 ns, 0.0234 ns/op
+// GC: 0 0 0 0 268435456
+// Threading: 0 0 268435456
+
+// AfterAll
+// Benchmark Process 517365 has exited with code 0.
+
+Mean = 0.008 ns, StdErr = 0.008 ns (100.00%), N = 3, StdDev = 0.013 ns
+Min = 0.000 ns, Q1 = 0.000 ns, Median = 0.000 ns, Q3 = 0.012 ns, Max = 0.023 ns
+IQR = 0.012 ns, LowerFence = -0.018 ns, UpperFence = 0.029 ns
+ConfidenceInterval = [-0.238 ns; 0.254 ns] (CI 99.9%), Margin = 0.246 ns (3159.91% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 1 (9.1 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// **************************
+// Benchmark: StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-ShortRun-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark --job ShortRun --benchmarkId 10 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-ShortRun-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+
+OverheadJitting 1: 1 op, 257645.00 ns, 257.6450 us/op
+WorkloadJitting 1: 1 op, 4007429.00 ns, 4.0074 ms/op
+
+OverheadJitting 2: 16 op, 678079.00 ns, 42.3799 us/op
+WorkloadJitting 2: 16 op, 710460.00 ns, 44.4038 us/op
+
+WorkloadPilot 1: 16 op, 12135.00 ns, 758.4375 ns/op
+WorkloadPilot 2: 32 op, 41586.00 ns, 1.2996 us/op
+WorkloadPilot 3: 64 op, 40652.00 ns, 635.1875 ns/op
+WorkloadPilot 4: 128 op, 78968.00 ns, 616.9375 ns/op
+WorkloadPilot 5: 256 op, 200059.00 ns, 781.4805 ns/op
+WorkloadPilot 6: 512 op, 412996.00 ns, 806.6328 ns/op
+WorkloadPilot 7: 1024 op, 718344.00 ns, 701.5078 ns/op
+WorkloadPilot 8: 2048 op, 1135964.00 ns, 554.6699 ns/op
+WorkloadPilot 9: 4096 op, 2187528.00 ns, 534.0645 ns/op
+WorkloadPilot 10: 8192 op, 4399191.00 ns, 537.0106 ns/op
+WorkloadPilot 11: 16384 op, 8529009.00 ns, 520.5694 ns/op
+WorkloadPilot 12: 32768 op, 16839289.00 ns, 513.8943 ns/op
+WorkloadPilot 13: 65536 op, 33268914.00 ns, 507.6433 ns/op
+WorkloadPilot 14: 131072 op, 59088069.00 ns, 450.8062 ns/op
+WorkloadPilot 15: 262144 op, 25558688.00 ns, 97.4987 ns/op
+WorkloadPilot 16: 524288 op, 46097170.00 ns, 87.9234 ns/op
+WorkloadPilot 17: 1048576 op, 93697323.00 ns, 89.3567 ns/op
+WorkloadPilot 18: 2097152 op, 181257960.00 ns, 86.4305 ns/op
+WorkloadPilot 19: 4194304 op, 376578755.00 ns, 89.7834 ns/op
+WorkloadPilot 20: 8388608 op, 722752837.00 ns, 86.1589 ns/op
+
+OverheadWarmup 1: 8388608 op, 39708549.00 ns, 4.7336 ns/op
+OverheadWarmup 2: 8388608 op, 40271781.00 ns, 4.8008 ns/op
+OverheadWarmup 3: 8388608 op, 40498872.00 ns, 4.8278 ns/op
+OverheadWarmup 4: 8388608 op, 40660031.00 ns, 4.8471 ns/op
+OverheadWarmup 5: 8388608 op, 39752641.00 ns, 4.7389 ns/op
+OverheadWarmup 6: 8388608 op, 39760916.00 ns, 4.7399 ns/op
+OverheadWarmup 7: 8388608 op, 39682426.00 ns, 4.7305 ns/op
+
+OverheadActual 1: 8388608 op, 39721729.00 ns, 4.7352 ns/op
+OverheadActual 2: 8388608 op, 39704362.00 ns, 4.7331 ns/op
+OverheadActual 3: 8388608 op, 39717640.00 ns, 4.7347 ns/op
+OverheadActual 4: 8388608 op, 40011663.00 ns, 4.7698 ns/op
+OverheadActual 5: 8388608 op, 40168616.00 ns, 4.7885 ns/op
+OverheadActual 6: 8388608 op, 40246242.00 ns, 4.7977 ns/op
+OverheadActual 7: 8388608 op, 40632028.00 ns, 4.8437 ns/op
+OverheadActual 8: 8388608 op, 35643907.00 ns, 4.2491 ns/op
+OverheadActual 9: 8388608 op, 33526371.00 ns, 3.9967 ns/op
+OverheadActual 10: 8388608 op, 33341784.00 ns, 3.9747 ns/op
+OverheadActual 11: 8388608 op, 37926071.00 ns, 4.5211 ns/op
+OverheadActual 12: 8388608 op, 33351341.00 ns, 3.9758 ns/op
+OverheadActual 13: 8388608 op, 32692893.00 ns, 3.8973 ns/op
+OverheadActual 14: 8388608 op, 32609358.00 ns, 3.8873 ns/op
+OverheadActual 15: 8388608 op, 32801623.00 ns, 3.9103 ns/op
+OverheadActual 16: 8388608 op, 32685540.00 ns, 3.8964 ns/op
+OverheadActual 17: 8388608 op, 32724684.00 ns, 3.9011 ns/op
+OverheadActual 18: 8388608 op, 32844391.00 ns, 3.9154 ns/op
+OverheadActual 19: 8388608 op, 32686515.00 ns, 3.8965 ns/op
+OverheadActual 20: 8388608 op, 32885021.00 ns, 3.9202 ns/op
+
+WorkloadWarmup 1: 8388608 op, 740612124.00 ns, 88.2878 ns/op
+WorkloadWarmup 2: 8388608 op, 735540381.00 ns, 87.6832 ns/op
+WorkloadWarmup 3: 8388608 op, 733947742.00 ns, 87.4934 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 8388608 op, 722283448.00 ns, 86.1029 ns/op
+WorkloadActual 2: 8388608 op, 767078911.00 ns, 91.4429 ns/op
+WorkloadActual 3: 8388608 op, 740716800.00 ns, 88.3003 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 8388608 op, 688844592.00 ns, 82.1167 ns/op
+WorkloadResult 2: 8388608 op, 733640055.00 ns, 87.4567 ns/op
+WorkloadResult 3: 8388608 op, 707277944.00 ns, 84.3141 ns/op
+// GC: 81 0 0 1409286144 8388608
+// Threading: 0 0 8388608
+
+// AfterAll
+// Benchmark Process 517893 has exited with code 0.
+
+Mean = 84.629 ns, StdErr = 1.550 ns (1.83%), N = 3, StdDev = 2.684 ns
+Min = 82.117 ns, Q1 = 83.215 ns, Median = 84.314 ns, Q3 = 85.885 ns, Max = 87.457 ns
+IQR = 2.670 ns, LowerFence = 79.210 ns, UpperFence = 89.890 ns
+ConfidenceInterval = [35.664 ns; 133.594 ns] (CI 99.9%), Margin = 48.965 ns (57.86% of Mean)
+Skewness = 0.12, Kurtosis = 0.67, MValue = 2
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-07 22:39 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html
+
+// * Detailed results *
+StringExtensionsBenchmarks.Linq: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 51.196 μs, StdErr = 0.051 μs (0.10%), N = 3, StdDev = 0.089 μs
+Min = 51.127 μs, Q1 = 51.145 μs, Median = 51.164 μs, Q3 = 51.230 μs, Max = 51.296 μs
+IQR = 0.084 μs, LowerFence = 51.019 μs, UpperFence = 51.356 μs
+ConfidenceInterval = [49.578 μs; 52.813 μs] (CI 99.9%), Margin = 1.617 μs (3.16% of Mean)
+Skewness = 0.31, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[51.047 μs ; 51.376 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToHeapStrings: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 37.355 μs, StdErr = 0.316 μs (0.85%), N = 3, StdDev = 0.548 μs
+Min = 36.818 μs, Q1 = 37.076 μs, Median = 37.334 μs, Q3 = 37.624 μs, Max = 37.913 μs
+IQR = 0.548 μs, LowerFence = 36.254 μs, UpperFence = 38.445 μs
+ConfidenceInterval = [27.355 μs; 47.354 μs] (CI 99.9%), Margin = 9.999 μs (26.77% of Mean)
+Skewness = 0.04, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[36.577 μs ; 37.575 μs) | @@
+[37.575 μs ; 38.412 μs) | @
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheckReversingListAsSpan: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 25.785 μs, StdErr = 0.062 μs (0.24%), N = 3, StdDev = 0.107 μs
+Min = 25.665 μs, Q1 = 25.742 μs, Median = 25.818 μs, Q3 = 25.845 μs, Max = 25.871 μs
+IQR = 0.103 μs, LowerFence = 25.588 μs, UpperFence = 25.999 μs
+ConfidenceInterval = [23.836 μs; 27.734 μs] (CI 99.9%), Margin = 1.949 μs (7.56% of Mean)
+Skewness = -0.28, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[25.568 μs ; 25.968 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithoutEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 26.442 μs, StdErr = 0.128 μs (0.49%), N = 3, StdDev = 0.222 μs
+Min = 26.186 μs, Q1 = 26.372 μs, Median = 26.557 μs, Q3 = 26.570 μs, Max = 26.582 μs
+IQR = 0.198 μs, LowerFence = 26.074 μs, UpperFence = 26.868 μs
+ConfidenceInterval = [22.387 μs; 30.497 μs] (CI 99.9%), Margin = 4.055 μs (15.33% of Mean)
+Skewness = -0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[26.182 μs ; 26.586 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.SplitToStackSpansWithEmptyCheck: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 25.822 μs, StdErr = 0.153 μs (0.59%), N = 3, StdDev = 0.265 μs
+Min = 25.624 μs, Q1 = 25.671 μs, Median = 25.718 μs, Q3 = 25.921 μs, Max = 26.123 μs
+IQR = 0.250 μs, LowerFence = 25.297 μs, UpperFence = 26.295 μs
+ConfidenceInterval = [20.982 μs; 30.662 μs] (CI 99.9%), Margin = 4.840 μs (18.75% of Mean)
+Skewness = 0.33, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[25.383 μs ; 26.365 μs) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripWhitespace_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 269.208 ns, StdErr = 1.475 ns (0.55%), N = 3, StdDev = 2.554 ns
+Min = 267.624 ns, Q1 = 267.735 ns, Median = 267.847 ns, Q3 = 270.001 ns, Max = 272.155 ns
+IQR = 2.266 ns, LowerFence = 264.337 ns, UpperFence = 273.399 ns
+ConfidenceInterval = [222.612 ns; 315.804 ns] (CI 99.9%), Margin = 46.596 ns (17.31% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[267.565 ns ; 272.214 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.GetFileExtension_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 308.982 ns, StdErr = 3.190 ns (1.03%), N = 3, StdDev = 5.526 ns
+Min = 303.132 ns, Q1 = 306.417 ns, Median = 309.701 ns, Q3 = 311.907 ns, Max = 314.113 ns
+IQR = 5.490 ns, LowerFence = 298.181 ns, UpperFence = 320.143 ns
+ConfidenceInterval = [208.173 ns; 409.791 ns] (CI 99.9%), Margin = 100.809 ns (32.63% of Mean)
+Skewness = -0.13, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[298.103 ns ; 306.878 ns) | @
+[306.878 ns ; 316.936 ns) | @@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.StripHtml_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 719.679 ns, StdErr = 5.775 ns (0.80%), N = 3, StdDev = 10.003 ns
+Min = 710.254 ns, Q1 = 714.431 ns, Median = 718.608 ns, Q3 = 724.391 ns, Max = 730.174 ns
+IQR = 9.960 ns, LowerFence = 699.491 ns, UpperFence = 739.331 ns
+ConfidenceInterval = [537.184 ns; 902.173 ns] (CI 99.9%), Margin = 182.495 ns (25.36% of Mean)
+Skewness = 0.11, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[705.328 ns ; 723.534 ns) | @@
+[723.534 ns ; 739.278 ns) | @
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 0.019 ns, StdErr = 0.007 ns (34.33%), N = 3, StdDev = 0.012 ns
+Min = 0.007 ns, Q1 = 0.014 ns, Median = 0.022 ns, Q3 = 0.026 ns, Max = 0.029 ns
+IQR = 0.011 ns, LowerFence = -0.003 ns, UpperFence = 0.043 ns
+ConfidenceInterval = [-0.191 ns; 0.230 ns] (CI 99.9%), Margin = 0.210 ns (1084.87% of Mean)
+Skewness = -0.2, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[0.007 ns ; 0.015 ns) | @
+[0.015 ns ; 0.040 ns) | @@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 0.008 ns, StdErr = 0.008 ns (100.00%), N = 3, StdDev = 0.013 ns
+Min = 0.000 ns, Q1 = 0.000 ns, Median = 0.000 ns, Q3 = 0.012 ns, Max = 0.023 ns
+IQR = 0.012 ns, LowerFence = -0.018 ns, UpperFence = 0.029 ns
+ConfidenceInterval = [-0.238 ns; 0.254 ns] (CI 99.9%), Margin = 0.246 ns (3159.91% of Mean)
+Skewness = 0.38, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[0.000 ns ; 0.024 ns) | @@@
+---------------------------------------------------
+
+StringExtensionsBenchmarks.ReplaceNonAlphanumericChars_String_Benchmark: ShortRun(IterationCount=3, LaunchCount=1, WarmupCount=3)
+Runtime = .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 84.629 ns, StdErr = 1.550 ns (1.83%), N = 3, StdDev = 2.684 ns
+Min = 82.117 ns, Q1 = 83.215 ns, Median = 84.314 ns, Q3 = 85.885 ns, Max = 87.457 ns
+IQR = 2.670 ns, LowerFence = 79.210 ns, UpperFence = 89.890 ns
+ConfidenceInterval = [35.664 ns; 133.594 ns] (CI 99.9%), Margin = 48.965 ns (57.86% of Mean)
+Skewness = 0.12, Kurtosis = 0.67, MValue = 2
+-------------------- Histogram --------------------
+[80.773 ns ; 85.658 ns) | @@
+[85.658 ns ; 89.899 ns) | @
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100-rc.2.25502.107
+ [Host] : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+
+Job=ShortRun IterationCount=3 LaunchCount=1
+WarmupCount=3
+
+| Method | Mean | Error | StdDev | Median | Gen0 | Allocated |
+|------------------------------------------------------ |---------------:|--------------:|------------:|---------------:|-------:|----------:|
+| Linq | 51,195.5380 ns | 1,617.4345 ns | 88.6570 ns | 51,163.7063 ns | 3.4180 | 59712 B |
+| SplitToHeapStrings | 37,354.8894 ns | 9,999.4406 ns | 548.1031 ns | 37,333.8901 ns | 2.5635 | 44592 B |
+| SplitToStackSpansWithoutEmptyCheckReversingListAsSpan | 25,784.9531 ns | 1,949.3238 ns | 106.8490 ns | 25,818.4337 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithoutEmptyCheck | 26,441.8317 ns | 4,054.8077 ns | 222.2577 ns | 26,557.4375 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithEmptyCheck | 25,821.9195 ns | 4,840.3751 ns | 265.3173 ns | 25,718.1962 ns | 0.9766 | 17128 B |
+| StripWhitespace_Benchmark | 269.2084 ns | 46.5960 ns | 2.5541 ns | 267.8466 ns | 0.0033 | 64 B |
+| GetFileExtension_Benchmark | 308.9820 ns | 100.8086 ns | 5.5257 ns | 309.7014 ns | 0.0319 | 552 B |
+| StripHtml_Benchmark | 719.6788 ns | 182.4947 ns | 10.0031 ns | 718.6075 ns | 0.0019 | 48 B |
+| IsLowerCase_Benchmark | 0.0194 ns | 0.2102 ns | 0.0115 ns | 0.0218 ns | - | - |
+| IsUpperCase_Benchmark | 0.0078 ns | 0.2461 ns | 0.0135 ns | 0.0000 ns | - | - |
+| ReplaceNonAlphanumericChars_String_Benchmark | 84.6292 ns | 48.9647 ns | 2.6839 ns | 84.3141 ns | 0.0097 | 168 B |
+
+// * Warnings *
+ZeroMeasurement
+ StringExtensionsBenchmarks.IsLowerCase_Benchmark: ShortRun -> The method duration is indistinguishable from the empty method duration
+ StringExtensionsBenchmarks.IsUpperCase_Benchmark: ShortRun -> The method duration is indistinguishable from the empty method duration
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Median : Value separating the higher half of all measurements (50th percentile)
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:01:40 (100.93 sec), executed benchmarks: 11
+
+Global total time: 00:03:22 (202.57 sec), executed benchmarks: 11
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-20251213-033947.log b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-20251213-033947.log
new file mode 100644
index 0000000000..0797486f8f
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-20251213-033947.log
@@ -0,0 +1,1358 @@
+// Validating benchmarks:
+// ***** BenchmarkRunner: Start *****
+// ***** Found 10 benchmark(s) in total *****
+// ***** Building 1 exe(s) in Parallel: Start *****
+// start dotnet restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/publish/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1
+// command took 3.96 sec and exited with 0
+// start dotnet build -c Release --no-restore --nodeReuse:false /p:UseSharedCompilation=false /p:Deterministic=true /p:Optimize=true /p:ArtifactsPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/" /p:OutDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0/" /p:OutputPath="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0/" /p:PublishDir="/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/publish/" --output "/home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0/" in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1
+// command took 95.16 sec and exited with 0
+// ***** Done, took 00:01:39 (99.39 sec) *****
+// Found 10 benchmarks:
+// Utf8ToAsciiConverterBenchmarks.Tiny_Ascii: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Tiny_Mixed: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Small_Ascii: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Small_Mixed: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Medium_Ascii: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Medium_Mixed: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Large_Ascii: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Large_Mixed: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Large_WorstCase: DefaultJob
+// Utf8ToAsciiConverterBenchmarks.Span_Medium_Mixed: DefaultJob
+
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Tiny_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Tiny_Ascii --job Default --benchmarkId 0 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 264559.00 ns, 264.5590 us/op
+WorkloadJitting 1: 1 op, 9563746.00 ns, 9.5637 ms/op
+
+OverheadJitting 2: 16 op, 649634.00 ns, 40.6021 us/op
+WorkloadJitting 2: 16 op, 732280.00 ns, 45.7675 us/op
+
+WorkloadPilot 1: 16 op, 2977.00 ns, 186.0625 ns/op
+WorkloadPilot 2: 32 op, 2547.00 ns, 79.5938 ns/op
+WorkloadPilot 3: 64 op, 3515.00 ns, 54.9219 ns/op
+WorkloadPilot 4: 128 op, 4441.00 ns, 34.6953 ns/op
+WorkloadPilot 5: 256 op, 7306.00 ns, 28.5391 ns/op
+WorkloadPilot 6: 512 op, 13646.00 ns, 26.6523 ns/op
+WorkloadPilot 7: 1024 op, 25962.00 ns, 25.3535 ns/op
+WorkloadPilot 8: 2048 op, 49634.00 ns, 24.2354 ns/op
+WorkloadPilot 9: 4096 op, 97074.00 ns, 23.6997 ns/op
+WorkloadPilot 10: 8192 op, 328855.00 ns, 40.1434 ns/op
+WorkloadPilot 11: 16384 op, 609295.00 ns, 37.1884 ns/op
+WorkloadPilot 12: 32768 op, 1259526.00 ns, 38.4377 ns/op
+WorkloadPilot 13: 65536 op, 2511207.00 ns, 38.3180 ns/op
+WorkloadPilot 14: 131072 op, 5191322.00 ns, 39.6066 ns/op
+WorkloadPilot 15: 262144 op, 10324279.00 ns, 39.3840 ns/op
+WorkloadPilot 16: 524288 op, 20106563.00 ns, 38.3502 ns/op
+WorkloadPilot 17: 1048576 op, 24996028.00 ns, 23.8381 ns/op
+WorkloadPilot 18: 2097152 op, 49523364.00 ns, 23.6146 ns/op
+WorkloadPilot 19: 4194304 op, 62233695.00 ns, 14.8377 ns/op
+WorkloadPilot 20: 8388608 op, 89463842.00 ns, 10.6649 ns/op
+WorkloadPilot 21: 16777216 op, 178045106.00 ns, 10.6123 ns/op
+WorkloadPilot 22: 33554432 op, 355617388.00 ns, 10.5982 ns/op
+WorkloadPilot 23: 67108864 op, 710218058.00 ns, 10.5831 ns/op
+
+OverheadWarmup 1: 67108864 op, 293922282.00 ns, 4.3798 ns/op
+OverheadWarmup 2: 67108864 op, 256013909.00 ns, 3.8149 ns/op
+OverheadWarmup 3: 67108864 op, 255721527.00 ns, 3.8105 ns/op
+OverheadWarmup 4: 67108864 op, 255240919.00 ns, 3.8034 ns/op
+OverheadWarmup 5: 67108864 op, 254691858.00 ns, 3.7952 ns/op
+OverheadWarmup 6: 67108864 op, 255943536.00 ns, 3.8139 ns/op
+OverheadWarmup 7: 67108864 op, 255880107.00 ns, 3.8129 ns/op
+OverheadWarmup 8: 67108864 op, 255605009.00 ns, 3.8088 ns/op
+OverheadWarmup 9: 67108864 op, 255476077.00 ns, 3.8069 ns/op
+OverheadWarmup 10: 67108864 op, 255520950.00 ns, 3.8076 ns/op
+
+OverheadActual 1: 67108864 op, 255715760.00 ns, 3.8105 ns/op
+OverheadActual 2: 67108864 op, 256078044.00 ns, 3.8159 ns/op
+OverheadActual 3: 67108864 op, 256437573.00 ns, 3.8212 ns/op
+OverheadActual 4: 67108864 op, 255543327.00 ns, 3.8079 ns/op
+OverheadActual 5: 67108864 op, 256613662.00 ns, 3.8238 ns/op
+OverheadActual 6: 67108864 op, 255341209.00 ns, 3.8049 ns/op
+OverheadActual 7: 67108864 op, 260615341.00 ns, 3.8835 ns/op
+OverheadActual 8: 67108864 op, 260747658.00 ns, 3.8854 ns/op
+OverheadActual 9: 67108864 op, 260812240.00 ns, 3.8864 ns/op
+OverheadActual 10: 67108864 op, 261445322.00 ns, 3.8958 ns/op
+OverheadActual 11: 67108864 op, 261582863.00 ns, 3.8979 ns/op
+OverheadActual 12: 67108864 op, 260869737.00 ns, 3.8873 ns/op
+OverheadActual 13: 67108864 op, 263628208.00 ns, 3.9284 ns/op
+OverheadActual 14: 67108864 op, 262147125.00 ns, 3.9063 ns/op
+OverheadActual 15: 67108864 op, 261007372.00 ns, 3.8893 ns/op
+
+WorkloadWarmup 1: 67108864 op, 713400095.00 ns, 10.6305 ns/op
+WorkloadWarmup 2: 67108864 op, 715128927.00 ns, 10.6563 ns/op
+WorkloadWarmup 3: 67108864 op, 717702006.00 ns, 10.6946 ns/op
+WorkloadWarmup 4: 67108864 op, 722187694.00 ns, 10.7614 ns/op
+WorkloadWarmup 5: 67108864 op, 719166201.00 ns, 10.7164 ns/op
+WorkloadWarmup 6: 67108864 op, 724433861.00 ns, 10.7949 ns/op
+WorkloadWarmup 7: 67108864 op, 714212804.00 ns, 10.6426 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 67108864 op, 724587560.00 ns, 10.7972 ns/op
+WorkloadActual 2: 67108864 op, 711681218.00 ns, 10.6049 ns/op
+WorkloadActual 3: 67108864 op, 708880182.00 ns, 10.5631 ns/op
+WorkloadActual 4: 67108864 op, 709849082.00 ns, 10.5776 ns/op
+WorkloadActual 5: 67108864 op, 710380094.00 ns, 10.5855 ns/op
+WorkloadActual 6: 67108864 op, 722407092.00 ns, 10.7647 ns/op
+WorkloadActual 7: 67108864 op, 726328834.00 ns, 10.8231 ns/op
+WorkloadActual 8: 67108864 op, 723418790.00 ns, 10.7798 ns/op
+WorkloadActual 9: 67108864 op, 715610803.00 ns, 10.6634 ns/op
+WorkloadActual 10: 67108864 op, 710080418.00 ns, 10.5810 ns/op
+WorkloadActual 11: 67108864 op, 710953739.00 ns, 10.5940 ns/op
+WorkloadActual 12: 67108864 op, 711501345.00 ns, 10.6022 ns/op
+WorkloadActual 13: 67108864 op, 709731236.00 ns, 10.5758 ns/op
+WorkloadActual 14: 67108864 op, 707487693.00 ns, 10.5424 ns/op
+WorkloadActual 15: 67108864 op, 709571425.00 ns, 10.5734 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 67108864 op, 463839902.00 ns, 6.9118 ns/op
+WorkloadResult 2: 67108864 op, 450933560.00 ns, 6.7194 ns/op
+WorkloadResult 3: 67108864 op, 448132524.00 ns, 6.6777 ns/op
+WorkloadResult 4: 67108864 op, 449101424.00 ns, 6.6921 ns/op
+WorkloadResult 5: 67108864 op, 449632436.00 ns, 6.7000 ns/op
+WorkloadResult 6: 67108864 op, 461659434.00 ns, 6.8793 ns/op
+WorkloadResult 7: 67108864 op, 465581176.00 ns, 6.9377 ns/op
+WorkloadResult 8: 67108864 op, 462671132.00 ns, 6.8943 ns/op
+WorkloadResult 9: 67108864 op, 454863145.00 ns, 6.7780 ns/op
+WorkloadResult 10: 67108864 op, 449332760.00 ns, 6.6956 ns/op
+WorkloadResult 11: 67108864 op, 450206081.00 ns, 6.7086 ns/op
+WorkloadResult 12: 67108864 op, 450753687.00 ns, 6.7168 ns/op
+WorkloadResult 13: 67108864 op, 448983578.00 ns, 6.6904 ns/op
+WorkloadResult 14: 67108864 op, 446740035.00 ns, 6.6569 ns/op
+WorkloadResult 15: 67108864 op, 448823767.00 ns, 6.6880 ns/op
+// GC: 0 0 0 0 67108864
+// Threading: 0 0 67108864
+
+// AfterAll
+// Benchmark Process 383497 has exited with code 0.
+
+Mean = 6.756 ns, StdErr = 0.025 ns (0.37%), N = 15, StdDev = 0.097 ns
+Min = 6.657 ns, Q1 = 6.691 ns, Median = 6.709 ns, Q3 = 6.829 ns, Max = 6.938 ns
+IQR = 0.137 ns, LowerFence = 6.485 ns, UpperFence = 7.035 ns
+ConfidenceInterval = [6.652 ns; 6.861 ns] (CI 99.9%), Margin = 0.104 ns (1.54% of Mean)
+Skewness = 0.81, Kurtosis = 1.83, MValue = 2
+
+// ** Remained 9 (90.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:45 (0h 3m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Tiny_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Tiny_Mixed --job Default --benchmarkId 1 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 296142.00 ns, 296.1420 us/op
+WorkloadJitting 1: 1 op, 9807017.00 ns, 9.8070 ms/op
+
+OverheadJitting 2: 16 op, 720597.00 ns, 45.0373 us/op
+WorkloadJitting 2: 16 op, 787047.00 ns, 49.1904 us/op
+
+WorkloadPilot 1: 16 op, 4547.00 ns, 284.1875 ns/op
+WorkloadPilot 2: 32 op, 3735.00 ns, 116.7188 ns/op
+WorkloadPilot 3: 64 op, 4231.00 ns, 66.1094 ns/op
+WorkloadPilot 4: 128 op, 7048.00 ns, 55.0625 ns/op
+WorkloadPilot 5: 256 op, 11400.00 ns, 44.5313 ns/op
+WorkloadPilot 6: 512 op, 21279.00 ns, 41.5605 ns/op
+WorkloadPilot 7: 1024 op, 37625.00 ns, 36.7432 ns/op
+WorkloadPilot 8: 2048 op, 64580.00 ns, 31.5332 ns/op
+WorkloadPilot 9: 4096 op, 113317.00 ns, 27.6653 ns/op
+WorkloadPilot 10: 8192 op, 240449.00 ns, 29.3517 ns/op
+WorkloadPilot 11: 16384 op, 400840.00 ns, 24.4653 ns/op
+WorkloadPilot 12: 32768 op, 808074.00 ns, 24.6605 ns/op
+WorkloadPilot 13: 65536 op, 1612482.00 ns, 24.6045 ns/op
+WorkloadPilot 14: 131072 op, 3162984.00 ns, 24.1317 ns/op
+WorkloadPilot 15: 262144 op, 6299976.00 ns, 24.0325 ns/op
+WorkloadPilot 16: 524288 op, 12636320.00 ns, 24.1019 ns/op
+WorkloadPilot 17: 1048576 op, 25049148.00 ns, 23.8887 ns/op
+WorkloadPilot 18: 2097152 op, 49704386.00 ns, 23.7009 ns/op
+WorkloadPilot 19: 4194304 op, 81577449.00 ns, 19.4496 ns/op
+WorkloadPilot 20: 8388608 op, 87155595.00 ns, 10.3898 ns/op
+WorkloadPilot 21: 16777216 op, 173457299.00 ns, 10.3389 ns/op
+WorkloadPilot 22: 33554432 op, 346934483.00 ns, 10.3395 ns/op
+WorkloadPilot 23: 67108864 op, 696911680.00 ns, 10.3848 ns/op
+
+OverheadWarmup 1: 67108864 op, 304901600.00 ns, 4.5434 ns/op
+OverheadWarmup 2: 67108864 op, 256596087.00 ns, 3.8236 ns/op
+OverheadWarmup 3: 67108864 op, 255457001.00 ns, 3.8066 ns/op
+OverheadWarmup 4: 67108864 op, 255430081.00 ns, 3.8062 ns/op
+OverheadWarmup 5: 67108864 op, 256192390.00 ns, 3.8176 ns/op
+OverheadWarmup 6: 67108864 op, 256126852.00 ns, 3.8166 ns/op
+OverheadWarmup 7: 67108864 op, 255632290.00 ns, 3.8092 ns/op
+OverheadWarmup 8: 67108864 op, 255724629.00 ns, 3.8106 ns/op
+OverheadWarmup 9: 67108864 op, 255306703.00 ns, 3.8044 ns/op
+
+OverheadActual 1: 67108864 op, 255779871.00 ns, 3.8114 ns/op
+OverheadActual 2: 67108864 op, 255408243.00 ns, 3.8059 ns/op
+OverheadActual 3: 67108864 op, 255456209.00 ns, 3.8066 ns/op
+OverheadActual 4: 67108864 op, 255273985.00 ns, 3.8039 ns/op
+OverheadActual 5: 67108864 op, 254845521.00 ns, 3.7975 ns/op
+OverheadActual 6: 67108864 op, 255013154.00 ns, 3.8000 ns/op
+OverheadActual 7: 67108864 op, 255649179.00 ns, 3.8095 ns/op
+OverheadActual 8: 67108864 op, 255718202.00 ns, 3.8105 ns/op
+OverheadActual 9: 67108864 op, 255004286.00 ns, 3.7999 ns/op
+OverheadActual 10: 67108864 op, 255067083.00 ns, 3.8008 ns/op
+OverheadActual 11: 67108864 op, 254891745.00 ns, 3.7982 ns/op
+OverheadActual 12: 67108864 op, 255282530.00 ns, 3.8040 ns/op
+OverheadActual 13: 67108864 op, 255432328.00 ns, 3.8062 ns/op
+OverheadActual 14: 67108864 op, 255420820.00 ns, 3.8061 ns/op
+OverheadActual 15: 67108864 op, 255191979.00 ns, 3.8027 ns/op
+
+WorkloadWarmup 1: 67108864 op, 694056421.00 ns, 10.3422 ns/op
+WorkloadWarmup 2: 67108864 op, 695016472.00 ns, 10.3566 ns/op
+WorkloadWarmup 3: 67108864 op, 693370720.00 ns, 10.3320 ns/op
+WorkloadWarmup 4: 67108864 op, 694762239.00 ns, 10.3528 ns/op
+WorkloadWarmup 5: 67108864 op, 694878888.00 ns, 10.3545 ns/op
+WorkloadWarmup 6: 67108864 op, 694795481.00 ns, 10.3533 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 67108864 op, 693535401.00 ns, 10.3345 ns/op
+WorkloadActual 2: 67108864 op, 694098072.00 ns, 10.3429 ns/op
+WorkloadActual 3: 67108864 op, 693908481.00 ns, 10.3400 ns/op
+WorkloadActual 4: 67108864 op, 694825686.00 ns, 10.3537 ns/op
+WorkloadActual 5: 67108864 op, 695698630.00 ns, 10.3667 ns/op
+WorkloadActual 6: 67108864 op, 696781682.00 ns, 10.3829 ns/op
+WorkloadActual 7: 67108864 op, 695304880.00 ns, 10.3609 ns/op
+WorkloadActual 8: 67108864 op, 696526108.00 ns, 10.3790 ns/op
+WorkloadActual 9: 67108864 op, 695723378.00 ns, 10.3671 ns/op
+WorkloadActual 10: 67108864 op, 694671184.00 ns, 10.3514 ns/op
+WorkloadActual 11: 67108864 op, 694863062.00 ns, 10.3543 ns/op
+WorkloadActual 12: 67108864 op, 695161073.00 ns, 10.3587 ns/op
+WorkloadActual 13: 67108864 op, 694203773.00 ns, 10.3444 ns/op
+WorkloadActual 14: 67108864 op, 695934108.00 ns, 10.3702 ns/op
+WorkloadActual 15: 67108864 op, 695901784.00 ns, 10.3697 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 67108864 op, 438252871.00 ns, 6.5305 ns/op
+WorkloadResult 2: 67108864 op, 438815542.00 ns, 6.5389 ns/op
+WorkloadResult 3: 67108864 op, 438625951.00 ns, 6.5360 ns/op
+WorkloadResult 4: 67108864 op, 439543156.00 ns, 6.5497 ns/op
+WorkloadResult 5: 67108864 op, 440416100.00 ns, 6.5627 ns/op
+WorkloadResult 6: 67108864 op, 441499152.00 ns, 6.5789 ns/op
+WorkloadResult 7: 67108864 op, 440022350.00 ns, 6.5568 ns/op
+WorkloadResult 8: 67108864 op, 441243578.00 ns, 6.5750 ns/op
+WorkloadResult 9: 67108864 op, 440440848.00 ns, 6.5631 ns/op
+WorkloadResult 10: 67108864 op, 439388654.00 ns, 6.5474 ns/op
+WorkloadResult 11: 67108864 op, 439580532.00 ns, 6.5503 ns/op
+WorkloadResult 12: 67108864 op, 439878543.00 ns, 6.5547 ns/op
+WorkloadResult 13: 67108864 op, 438921243.00 ns, 6.5404 ns/op
+WorkloadResult 14: 67108864 op, 440651578.00 ns, 6.5662 ns/op
+WorkloadResult 15: 67108864 op, 440619254.00 ns, 6.5657 ns/op
+// GC: 0 0 0 0 67108864
+// Threading: 0 0 67108864
+
+// AfterAll
+// Benchmark Process 383609 has exited with code 0.
+
+Mean = 6.554 ns, StdErr = 0.004 ns (0.06%), N = 15, StdDev = 0.014 ns
+Min = 6.530 ns, Q1 = 6.544 ns, Median = 6.555 ns, Q3 = 6.564 ns, Max = 6.579 ns
+IQR = 0.020 ns, LowerFence = 6.513 ns, UpperFence = 6.595 ns
+ConfidenceInterval = [6.539 ns; 6.570 ns] (CI 99.9%), Margin = 0.015 ns (0.23% of Mean)
+Skewness = 0.02, Kurtosis = 1.78, MValue = 2
+
+// ** Remained 8 (80.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:45 (0h 3m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Small_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Small_Ascii --job Default --benchmarkId 2 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 282671.00 ns, 282.6710 us/op
+WorkloadJitting 1: 1 op, 10001619.00 ns, 10.0016 ms/op
+
+OverheadJitting 2: 16 op, 672189.00 ns, 42.0118 us/op
+WorkloadJitting 2: 16 op, 749679.00 ns, 46.8549 us/op
+
+WorkloadPilot 1: 16 op, 3716.00 ns, 232.2500 ns/op
+WorkloadPilot 2: 32 op, 3467.00 ns, 108.3438 ns/op
+WorkloadPilot 3: 64 op, 4148.00 ns, 64.8125 ns/op
+WorkloadPilot 4: 128 op, 21676.00 ns, 169.3438 ns/op
+WorkloadPilot 5: 256 op, 9363.00 ns, 36.5742 ns/op
+WorkloadPilot 6: 512 op, 16952.00 ns, 33.1094 ns/op
+WorkloadPilot 7: 1024 op, 32502.00 ns, 31.7402 ns/op
+WorkloadPilot 8: 2048 op, 63354.00 ns, 30.9346 ns/op
+WorkloadPilot 9: 4096 op, 125452.00 ns, 30.6279 ns/op
+WorkloadPilot 10: 8192 op, 268552.00 ns, 32.7822 ns/op
+WorkloadPilot 11: 16384 op, 508927.00 ns, 31.0624 ns/op
+WorkloadPilot 12: 32768 op, 1043633.00 ns, 31.8492 ns/op
+WorkloadPilot 13: 65536 op, 2018246.00 ns, 30.7960 ns/op
+WorkloadPilot 14: 131072 op, 4081104.00 ns, 31.1364 ns/op
+WorkloadPilot 15: 262144 op, 8085367.00 ns, 30.8432 ns/op
+WorkloadPilot 16: 524288 op, 16148595.00 ns, 30.8010 ns/op
+WorkloadPilot 17: 1048576 op, 32285628.00 ns, 30.7900 ns/op
+WorkloadPilot 18: 2097152 op, 64295170.00 ns, 30.6583 ns/op
+WorkloadPilot 19: 4194304 op, 68540305.00 ns, 16.3413 ns/op
+WorkloadPilot 20: 8388608 op, 100757449.00 ns, 12.0112 ns/op
+WorkloadPilot 21: 16777216 op, 201867726.00 ns, 12.0323 ns/op
+WorkloadPilot 22: 33554432 op, 403436452.00 ns, 12.0233 ns/op
+WorkloadPilot 23: 67108864 op, 808515716.00 ns, 12.0478 ns/op
+
+OverheadWarmup 1: 67108864 op, 297803483.00 ns, 4.4376 ns/op
+OverheadWarmup 2: 67108864 op, 260695603.00 ns, 3.8847 ns/op
+OverheadWarmup 3: 67108864 op, 260135862.00 ns, 3.8763 ns/op
+OverheadWarmup 4: 67108864 op, 260694985.00 ns, 3.8847 ns/op
+OverheadWarmup 5: 67108864 op, 260517437.00 ns, 3.8820 ns/op
+OverheadWarmup 6: 67108864 op, 260894914.00 ns, 3.8876 ns/op
+OverheadWarmup 7: 67108864 op, 261422427.00 ns, 3.8955 ns/op
+OverheadWarmup 8: 67108864 op, 260260552.00 ns, 3.8782 ns/op
+
+OverheadActual 1: 67108864 op, 260148674.00 ns, 3.8765 ns/op
+OverheadActual 2: 67108864 op, 259884175.00 ns, 3.8726 ns/op
+OverheadActual 3: 67108864 op, 260705156.00 ns, 3.8848 ns/op
+OverheadActual 4: 67108864 op, 260393835.00 ns, 3.8802 ns/op
+OverheadActual 5: 67108864 op, 260527260.00 ns, 3.8822 ns/op
+OverheadActual 6: 67108864 op, 260753504.00 ns, 3.8855 ns/op
+OverheadActual 7: 67108864 op, 260615068.00 ns, 3.8835 ns/op
+OverheadActual 8: 67108864 op, 260239629.00 ns, 3.8779 ns/op
+OverheadActual 9: 67108864 op, 260232749.00 ns, 3.8778 ns/op
+OverheadActual 10: 67108864 op, 260304593.00 ns, 3.8788 ns/op
+OverheadActual 11: 67108864 op, 260919410.00 ns, 3.8880 ns/op
+OverheadActual 12: 67108864 op, 260285288.00 ns, 3.8786 ns/op
+OverheadActual 13: 67108864 op, 260221192.00 ns, 3.8776 ns/op
+OverheadActual 14: 67108864 op, 260230851.00 ns, 3.8777 ns/op
+OverheadActual 15: 67108864 op, 261072180.00 ns, 3.8903 ns/op
+
+WorkloadWarmup 1: 67108864 op, 806007575.00 ns, 12.0104 ns/op
+WorkloadWarmup 2: 67108864 op, 804235437.00 ns, 11.9840 ns/op
+WorkloadWarmup 3: 67108864 op, 805667736.00 ns, 12.0054 ns/op
+WorkloadWarmup 4: 67108864 op, 807838582.00 ns, 12.0377 ns/op
+WorkloadWarmup 5: 67108864 op, 804528261.00 ns, 11.9884 ns/op
+WorkloadWarmup 6: 67108864 op, 804910259.00 ns, 11.9941 ns/op
+WorkloadWarmup 7: 67108864 op, 804735584.00 ns, 11.9915 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 67108864 op, 804785103.00 ns, 11.9922 ns/op
+WorkloadActual 2: 67108864 op, 807080495.00 ns, 12.0264 ns/op
+WorkloadActual 3: 67108864 op, 806559130.00 ns, 12.0187 ns/op
+WorkloadActual 4: 67108864 op, 806403608.00 ns, 12.0164 ns/op
+WorkloadActual 5: 67108864 op, 803587839.00 ns, 11.9744 ns/op
+WorkloadActual 6: 67108864 op, 804179248.00 ns, 11.9832 ns/op
+WorkloadActual 7: 67108864 op, 804144436.00 ns, 11.9827 ns/op
+WorkloadActual 8: 67108864 op, 806653169.00 ns, 12.0201 ns/op
+WorkloadActual 9: 67108864 op, 807653223.00 ns, 12.0350 ns/op
+WorkloadActual 10: 67108864 op, 805384162.00 ns, 12.0012 ns/op
+WorkloadActual 11: 67108864 op, 807211095.00 ns, 12.0284 ns/op
+WorkloadActual 12: 67108864 op, 805660741.00 ns, 12.0053 ns/op
+WorkloadActual 13: 67108864 op, 809197059.00 ns, 12.0580 ns/op
+WorkloadActual 14: 67108864 op, 803647466.00 ns, 11.9753 ns/op
+WorkloadActual 15: 67108864 op, 807974111.00 ns, 12.0398 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 67108864 op, 544480510.00 ns, 8.1134 ns/op
+WorkloadResult 2: 67108864 op, 546775902.00 ns, 8.1476 ns/op
+WorkloadResult 3: 67108864 op, 546254537.00 ns, 8.1398 ns/op
+WorkloadResult 4: 67108864 op, 546099015.00 ns, 8.1375 ns/op
+WorkloadResult 5: 67108864 op, 543283246.00 ns, 8.0956 ns/op
+WorkloadResult 6: 67108864 op, 543874655.00 ns, 8.1044 ns/op
+WorkloadResult 7: 67108864 op, 543839843.00 ns, 8.1038 ns/op
+WorkloadResult 8: 67108864 op, 546348576.00 ns, 8.1412 ns/op
+WorkloadResult 9: 67108864 op, 547348630.00 ns, 8.1561 ns/op
+WorkloadResult 10: 67108864 op, 545079569.00 ns, 8.1223 ns/op
+WorkloadResult 11: 67108864 op, 546906502.00 ns, 8.1495 ns/op
+WorkloadResult 12: 67108864 op, 545356148.00 ns, 8.1264 ns/op
+WorkloadResult 13: 67108864 op, 548892466.00 ns, 8.1791 ns/op
+WorkloadResult 14: 67108864 op, 543342873.00 ns, 8.0964 ns/op
+WorkloadResult 15: 67108864 op, 547669518.00 ns, 8.1609 ns/op
+// GC: 0 0 0 0 67108864
+// Threading: 0 0 67108864
+
+// AfterAll
+// Benchmark Process 383721 has exited with code 0.
+
+Mean = 8.132 ns, StdErr = 0.007 ns (0.08%), N = 15, StdDev = 0.025 ns
+Min = 8.096 ns, Q1 = 8.109 ns, Median = 8.138 ns, Q3 = 8.149 ns, Max = 8.179 ns
+IQR = 0.040 ns, LowerFence = 8.049 ns, UpperFence = 8.208 ns
+ConfidenceInterval = [8.105 ns; 8.159 ns] (CI 99.9%), Margin = 0.027 ns (0.33% of Mean)
+Skewness = 0.08, Kurtosis = 1.76, MValue = 2
+
+// ** Remained 7 (70.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:45 (0h 2m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Small_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Small_Mixed --job Default --benchmarkId 3 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 267343.00 ns, 267.3430 us/op
+WorkloadJitting 1: 1 op, 12094010.00 ns, 12.0940 ms/op
+
+OverheadJitting 2: 16 op, 684817.00 ns, 42.8011 us/op
+WorkloadJitting 2: 16 op, 749869.00 ns, 46.8668 us/op
+
+WorkloadPilot 1: 16 op, 53086.00 ns, 3.3179 us/op
+WorkloadPilot 2: 32 op, 100411.00 ns, 3.1378 us/op
+WorkloadPilot 3: 64 op, 137116.00 ns, 2.1424 us/op
+WorkloadPilot 4: 128 op, 247607.00 ns, 1.9344 us/op
+WorkloadPilot 5: 256 op, 417788.00 ns, 1.6320 us/op
+WorkloadPilot 6: 512 op, 924432.00 ns, 1.8055 us/op
+WorkloadPilot 7: 1024 op, 1818814.00 ns, 1.7762 us/op
+WorkloadPilot 8: 2048 op, 3464642.00 ns, 1.6917 us/op
+WorkloadPilot 9: 4096 op, 6630835.00 ns, 1.6189 us/op
+WorkloadPilot 10: 8192 op, 13577013.00 ns, 1.6574 us/op
+WorkloadPilot 11: 16384 op, 26440313.00 ns, 1.6138 us/op
+WorkloadPilot 12: 32768 op, 53332318.00 ns, 1.6276 us/op
+WorkloadPilot 13: 65536 op, 81088909.00 ns, 1.2373 us/op
+WorkloadPilot 14: 131072 op, 45950900.00 ns, 350.5775 ns/op
+WorkloadPilot 15: 262144 op, 84232854.00 ns, 321.3228 ns/op
+WorkloadPilot 16: 524288 op, 170756632.00 ns, 325.6924 ns/op
+WorkloadPilot 17: 1048576 op, 329475416.00 ns, 314.2122 ns/op
+WorkloadPilot 18: 2097152 op, 654868483.00 ns, 312.2656 ns/op
+
+OverheadWarmup 1: 2097152 op, 10562175.00 ns, 5.0364 ns/op
+OverheadWarmup 2: 2097152 op, 10566808.00 ns, 5.0386 ns/op
+OverheadWarmup 3: 2097152 op, 10531451.00 ns, 5.0218 ns/op
+OverheadWarmup 4: 2097152 op, 10569086.00 ns, 5.0397 ns/op
+OverheadWarmup 5: 2097152 op, 10557748.00 ns, 5.0343 ns/op
+
+OverheadActual 1: 2097152 op, 10529329.00 ns, 5.0208 ns/op
+OverheadActual 2: 2097152 op, 10558122.00 ns, 5.0345 ns/op
+OverheadActual 3: 2097152 op, 10548656.00 ns, 5.0300 ns/op
+OverheadActual 4: 2097152 op, 10562251.00 ns, 5.0365 ns/op
+OverheadActual 5: 2097152 op, 10686619.00 ns, 5.0958 ns/op
+OverheadActual 6: 2097152 op, 10521338.00 ns, 5.0170 ns/op
+OverheadActual 7: 2097152 op, 10554310.00 ns, 5.0327 ns/op
+OverheadActual 8: 2097152 op, 10537646.00 ns, 5.0247 ns/op
+OverheadActual 9: 2097152 op, 10529408.00 ns, 5.0208 ns/op
+OverheadActual 10: 2097152 op, 10551394.00 ns, 5.0313 ns/op
+OverheadActual 11: 2097152 op, 10728495.00 ns, 5.1157 ns/op
+OverheadActual 12: 2097152 op, 10604375.00 ns, 5.0566 ns/op
+OverheadActual 13: 2097152 op, 10611067.00 ns, 5.0598 ns/op
+OverheadActual 14: 2097152 op, 10587542.00 ns, 5.0485 ns/op
+OverheadActual 15: 2097152 op, 10568287.00 ns, 5.0394 ns/op
+
+WorkloadWarmup 1: 2097152 op, 670756229.00 ns, 319.8415 ns/op
+WorkloadWarmup 2: 2097152 op, 672189070.00 ns, 320.5247 ns/op
+WorkloadWarmup 3: 2097152 op, 656344335.00 ns, 312.9694 ns/op
+WorkloadWarmup 4: 2097152 op, 660574370.00 ns, 314.9864 ns/op
+WorkloadWarmup 5: 2097152 op, 656627163.00 ns, 313.1042 ns/op
+WorkloadWarmup 6: 2097152 op, 658037741.00 ns, 313.7768 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 2097152 op, 656818832.00 ns, 313.1956 ns/op
+WorkloadActual 2: 2097152 op, 656425759.00 ns, 313.0082 ns/op
+WorkloadActual 3: 2097152 op, 658401518.00 ns, 313.9503 ns/op
+WorkloadActual 4: 2097152 op, 660236313.00 ns, 314.8252 ns/op
+WorkloadActual 5: 2097152 op, 658194104.00 ns, 313.8514 ns/op
+WorkloadActual 6: 2097152 op, 660947925.00 ns, 315.1645 ns/op
+WorkloadActual 7: 2097152 op, 659218232.00 ns, 314.3397 ns/op
+WorkloadActual 8: 2097152 op, 659610030.00 ns, 314.5266 ns/op
+WorkloadActual 9: 2097152 op, 658686685.00 ns, 314.0863 ns/op
+WorkloadActual 10: 2097152 op, 659443285.00 ns, 314.4471 ns/op
+WorkloadActual 11: 2097152 op, 656746794.00 ns, 313.1613 ns/op
+WorkloadActual 12: 2097152 op, 657789079.00 ns, 313.6583 ns/op
+WorkloadActual 13: 2097152 op, 656685213.00 ns, 313.1319 ns/op
+WorkloadActual 14: 2097152 op, 657643747.00 ns, 313.5890 ns/op
+WorkloadActual 15: 2097152 op, 658509164.00 ns, 314.0016 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 2097152 op, 646260710.00 ns, 308.1611 ns/op
+WorkloadResult 2: 2097152 op, 645867637.00 ns, 307.9737 ns/op
+WorkloadResult 3: 2097152 op, 647843396.00 ns, 308.9158 ns/op
+WorkloadResult 4: 2097152 op, 649678191.00 ns, 309.7907 ns/op
+WorkloadResult 5: 2097152 op, 647635982.00 ns, 308.8169 ns/op
+WorkloadResult 6: 2097152 op, 650389803.00 ns, 310.1300 ns/op
+WorkloadResult 7: 2097152 op, 648660110.00 ns, 309.3052 ns/op
+WorkloadResult 8: 2097152 op, 649051908.00 ns, 309.4921 ns/op
+WorkloadResult 9: 2097152 op, 648128563.00 ns, 309.0518 ns/op
+WorkloadResult 10: 2097152 op, 648885163.00 ns, 309.4126 ns/op
+WorkloadResult 11: 2097152 op, 646188672.00 ns, 308.1268 ns/op
+WorkloadResult 12: 2097152 op, 647230957.00 ns, 308.6238 ns/op
+WorkloadResult 13: 2097152 op, 646127091.00 ns, 308.0974 ns/op
+WorkloadResult 14: 2097152 op, 647085625.00 ns, 308.5545 ns/op
+WorkloadResult 15: 2097152 op, 647951042.00 ns, 308.9671 ns/op
+// GC: 27 0 0 469762048 2097152
+// Threading: 0 0 2097152
+
+// AfterAll
+// Benchmark Process 383821 has exited with code 0.
+
+Mean = 308.895 ns, StdErr = 0.168 ns (0.05%), N = 15, StdDev = 0.652 ns
+Min = 307.974 ns, Q1 = 308.358 ns, Median = 308.916 ns, Q3 = 309.359 ns, Max = 310.130 ns
+IQR = 1.001 ns, LowerFence = 306.856 ns, UpperFence = 310.861 ns
+ConfidenceInterval = [308.197 ns; 309.592 ns] (CI 99.9%), Margin = 0.698 ns (0.23% of Mean)
+Skewness = 0.2, Kurtosis = 1.83, MValue = 2
+
+// ** Remained 6 (60.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:45 (0h 2m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Medium_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Medium_Ascii --job Default --benchmarkId 4 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 261042.00 ns, 261.0420 us/op
+WorkloadJitting 1: 1 op, 9544068.00 ns, 9.5441 ms/op
+
+OverheadJitting 2: 16 op, 653800.00 ns, 40.8625 us/op
+WorkloadJitting 2: 16 op, 704252.00 ns, 44.0158 us/op
+
+WorkloadPilot 1: 16 op, 5240.00 ns, 327.5000 ns/op
+WorkloadPilot 2: 32 op, 6288.00 ns, 196.5000 ns/op
+WorkloadPilot 3: 64 op, 9168.00 ns, 143.2500 ns/op
+WorkloadPilot 4: 128 op, 16545.00 ns, 129.2578 ns/op
+WorkloadPilot 5: 256 op, 31018.00 ns, 121.1641 ns/op
+WorkloadPilot 6: 512 op, 59476.00 ns, 116.1641 ns/op
+WorkloadPilot 7: 1024 op, 117469.00 ns, 114.7158 ns/op
+WorkloadPilot 8: 2048 op, 253171.00 ns, 123.6187 ns/op
+WorkloadPilot 9: 4096 op, 481245.00 ns, 117.4915 ns/op
+WorkloadPilot 10: 8192 op, 966840.00 ns, 118.0225 ns/op
+WorkloadPilot 11: 16384 op, 1881537.00 ns, 114.8399 ns/op
+WorkloadPilot 12: 32768 op, 3756963.00 ns, 114.6534 ns/op
+WorkloadPilot 13: 65536 op, 7588061.00 ns, 115.7846 ns/op
+WorkloadPilot 14: 131072 op, 15097333.00 ns, 115.1835 ns/op
+WorkloadPilot 15: 262144 op, 30172468.00 ns, 115.0988 ns/op
+WorkloadPilot 16: 524288 op, 60295019.00 ns, 115.0036 ns/op
+WorkloadPilot 17: 1048576 op, 68888623.00 ns, 65.6973 ns/op
+WorkloadPilot 18: 2097152 op, 88492087.00 ns, 42.1963 ns/op
+WorkloadPilot 19: 4194304 op, 177014626.00 ns, 42.2036 ns/op
+WorkloadPilot 20: 8388608 op, 352326413.00 ns, 42.0006 ns/op
+WorkloadPilot 21: 16777216 op, 704934605.00 ns, 42.0174 ns/op
+
+OverheadWarmup 1: 16777216 op, 84795287.00 ns, 5.0542 ns/op
+OverheadWarmup 2: 16777216 op, 84870409.00 ns, 5.0587 ns/op
+OverheadWarmup 3: 16777216 op, 71081368.00 ns, 4.2368 ns/op
+OverheadWarmup 4: 16777216 op, 64146890.00 ns, 3.8235 ns/op
+OverheadWarmup 5: 16777216 op, 64027875.00 ns, 3.8164 ns/op
+OverheadWarmup 6: 16777216 op, 64102680.00 ns, 3.8208 ns/op
+OverheadWarmup 7: 16777216 op, 63994882.00 ns, 3.8144 ns/op
+
+OverheadActual 1: 16777216 op, 64121519.00 ns, 3.8219 ns/op
+OverheadActual 2: 16777216 op, 64511877.00 ns, 3.8452 ns/op
+OverheadActual 3: 16777216 op, 64388280.00 ns, 3.8378 ns/op
+OverheadActual 4: 16777216 op, 64245752.00 ns, 3.8293 ns/op
+OverheadActual 5: 16777216 op, 64279492.00 ns, 3.8314 ns/op
+OverheadActual 6: 16777216 op, 64230508.00 ns, 3.8284 ns/op
+OverheadActual 7: 16777216 op, 64288244.00 ns, 3.8319 ns/op
+OverheadActual 8: 16777216 op, 64200585.00 ns, 3.8267 ns/op
+OverheadActual 9: 16777216 op, 64159890.00 ns, 3.8242 ns/op
+OverheadActual 10: 16777216 op, 64247406.00 ns, 3.8294 ns/op
+OverheadActual 11: 16777216 op, 64272083.00 ns, 3.8309 ns/op
+OverheadActual 12: 16777216 op, 64359366.00 ns, 3.8361 ns/op
+OverheadActual 13: 16777216 op, 64205083.00 ns, 3.8269 ns/op
+OverheadActual 14: 16777216 op, 64129066.00 ns, 3.8224 ns/op
+OverheadActual 15: 16777216 op, 64136646.00 ns, 3.8228 ns/op
+
+WorkloadWarmup 1: 16777216 op, 704567587.00 ns, 41.9955 ns/op
+WorkloadWarmup 2: 16777216 op, 703005316.00 ns, 41.9024 ns/op
+WorkloadWarmup 3: 16777216 op, 701336650.00 ns, 41.8029 ns/op
+WorkloadWarmup 4: 16777216 op, 707493119.00 ns, 42.1699 ns/op
+WorkloadWarmup 5: 16777216 op, 703436489.00 ns, 41.9281 ns/op
+WorkloadWarmup 6: 16777216 op, 702524997.00 ns, 41.8738 ns/op
+WorkloadWarmup 7: 16777216 op, 705374843.00 ns, 42.0436 ns/op
+WorkloadWarmup 8: 16777216 op, 704243829.00 ns, 41.9762 ns/op
+
+// BeforeActualRun
+WorkloadActual 1: 16777216 op, 710889169.00 ns, 42.3723 ns/op
+WorkloadActual 2: 16777216 op, 708948070.00 ns, 42.2566 ns/op
+WorkloadActual 3: 16777216 op, 702190268.00 ns, 41.8538 ns/op
+WorkloadActual 4: 16777216 op, 702854304.00 ns, 41.8934 ns/op
+WorkloadActual 5: 16777216 op, 699976557.00 ns, 41.7219 ns/op
+WorkloadActual 6: 16777216 op, 710378179.00 ns, 42.3418 ns/op
+WorkloadActual 7: 16777216 op, 705011723.00 ns, 42.0220 ns/op
+WorkloadActual 8: 16777216 op, 701230193.00 ns, 41.7966 ns/op
+WorkloadActual 9: 16777216 op, 703348871.00 ns, 41.9229 ns/op
+WorkloadActual 10: 16777216 op, 703185517.00 ns, 41.9131 ns/op
+WorkloadActual 11: 16777216 op, 706611460.00 ns, 42.1173 ns/op
+WorkloadActual 12: 16777216 op, 705794951.00 ns, 42.0687 ns/op
+WorkloadActual 13: 16777216 op, 705085156.00 ns, 42.0264 ns/op
+WorkloadActual 14: 16777216 op, 703308165.00 ns, 41.9204 ns/op
+WorkloadActual 15: 16777216 op, 708098962.00 ns, 42.2060 ns/op
+
+// AfterActualRun
+WorkloadResult 1: 16777216 op, 646643417.00 ns, 38.5430 ns/op
+WorkloadResult 2: 16777216 op, 644702318.00 ns, 38.4273 ns/op
+WorkloadResult 3: 16777216 op, 637944516.00 ns, 38.0245 ns/op
+WorkloadResult 4: 16777216 op, 638608552.00 ns, 38.0640 ns/op
+WorkloadResult 5: 16777216 op, 635730805.00 ns, 37.8925 ns/op
+WorkloadResult 6: 16777216 op, 646132427.00 ns, 38.5125 ns/op
+WorkloadResult 7: 16777216 op, 640765971.00 ns, 38.1926 ns/op
+WorkloadResult 8: 16777216 op, 636984441.00 ns, 37.9672 ns/op
+WorkloadResult 9: 16777216 op, 639103119.00 ns, 38.0935 ns/op
+WorkloadResult 10: 16777216 op, 638939765.00 ns, 38.0838 ns/op
+WorkloadResult 11: 16777216 op, 642365708.00 ns, 38.2880 ns/op
+WorkloadResult 12: 16777216 op, 641549199.00 ns, 38.2393 ns/op
+WorkloadResult 13: 16777216 op, 640839404.00 ns, 38.1970 ns/op
+WorkloadResult 14: 16777216 op, 639062413.00 ns, 38.0911 ns/op
+WorkloadResult 15: 16777216 op, 643853210.00 ns, 38.3766 ns/op
+// GC: 0 0 0 0 16777216
+// Threading: 0 0 16777216
+
+// AfterAll
+// Benchmark Process 383889 has exited with code 0.
+
+Mean = 38.200 ns, StdErr = 0.051 ns (0.13%), N = 15, StdDev = 0.197 ns
+Min = 37.893 ns, Q1 = 38.074 ns, Median = 38.193 ns, Q3 = 38.332 ns, Max = 38.543 ns
+IQR = 0.258 ns, LowerFence = 37.686 ns, UpperFence = 38.720 ns
+ConfidenceInterval = [37.989 ns; 38.410 ns] (CI 99.9%), Margin = 0.210 ns (0.55% of Mean)
+Skewness = 0.31, Kurtosis = 1.81, MValue = 2
+
+// ** Remained 5 (50.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:45 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Medium_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Medium_Mixed --job Default --benchmarkId 5 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 304146.00 ns, 304.1460 us/op
+WorkloadJitting 1: 1 op, 12539614.00 ns, 12.5396 ms/op
+
+OverheadJitting 2: 16 op, 673110.00 ns, 42.0694 us/op
+WorkloadJitting 2: 16 op, 1191245.00 ns, 74.4528 us/op
+
+WorkloadPilot 1: 16 op, 432860.00 ns, 27.0538 us/op
+WorkloadPilot 2: 32 op, 843418.00 ns, 26.3568 us/op
+WorkloadPilot 3: 64 op, 1720584.00 ns, 26.8841 us/op
+WorkloadPilot 4: 128 op, 3098571.00 ns, 24.2076 us/op
+WorkloadPilot 5: 256 op, 6206926.00 ns, 24.2458 us/op
+WorkloadPilot 6: 512 op, 12206554.00 ns, 23.8409 us/op
+WorkloadPilot 7: 1024 op, 24444206.00 ns, 23.8713 us/op
+WorkloadPilot 8: 2048 op, 48191725.00 ns, 23.5311 us/op
+WorkloadPilot 9: 4096 op, 93409565.00 ns, 22.8051 us/op
+WorkloadPilot 10: 8192 op, 45823926.00 ns, 5.5937 us/op
+WorkloadPilot 11: 16384 op, 70013644.00 ns, 4.2733 us/op
+WorkloadPilot 12: 32768 op, 137683389.00 ns, 4.2018 us/op
+WorkloadPilot 13: 65536 op, 273427209.00 ns, 4.1722 us/op
+WorkloadPilot 14: 131072 op, 547902124.00 ns, 4.1802 us/op
+
+OverheadWarmup 1: 131072 op, 602308.00 ns, 4.5952 ns/op
+OverheadWarmup 2: 131072 op, 578569.00 ns, 4.4141 ns/op
+OverheadWarmup 3: 131072 op, 600893.00 ns, 4.5844 ns/op
+OverheadWarmup 4: 131072 op, 582854.00 ns, 4.4468 ns/op
+OverheadWarmup 5: 131072 op, 601136.00 ns, 4.5863 ns/op
+OverheadWarmup 6: 131072 op, 581874.00 ns, 4.4393 ns/op
+
+OverheadActual 1: 131072 op, 598237.00 ns, 4.5642 ns/op
+OverheadActual 2: 131072 op, 578430.00 ns, 4.4131 ns/op
+OverheadActual 3: 131072 op, 578837.00 ns, 4.4162 ns/op
+OverheadActual 4: 131072 op, 579324.00 ns, 4.4199 ns/op
+OverheadActual 5: 131072 op, 579973.00 ns, 4.4248 ns/op
+OverheadActual 6: 131072 op, 595643.00 ns, 4.5444 ns/op
+OverheadActual 7: 131072 op, 573224.00 ns, 4.3734 ns/op
+OverheadActual 8: 131072 op, 604377.00 ns, 4.6110 ns/op
+OverheadActual 9: 131072 op, 569936.00 ns, 4.3483 ns/op
+OverheadActual 10: 131072 op, 598705.00 ns, 4.5678 ns/op
+OverheadActual 11: 131072 op, 592597.00 ns, 4.5212 ns/op
+OverheadActual 12: 131072 op, 599882.00 ns, 4.5767 ns/op
+OverheadActual 13: 131072 op, 590163.00 ns, 4.5026 ns/op
+OverheadActual 14: 131072 op, 582265.00 ns, 4.4423 ns/op
+OverheadActual 15: 131072 op, 603017.00 ns, 4.6007 ns/op
+
+WorkloadWarmup 1: 131072 op, 553581094.00 ns, 4.2235 us/op
+WorkloadWarmup 2: 131072 op, 554033309.00 ns, 4.2269 us/op
+WorkloadWarmup 3: 131072 op, 549863206.00 ns, 4.1951 us/op
+WorkloadWarmup 4: 131072 op, 550312671.00 ns, 4.1986 us/op
+WorkloadWarmup 5: 131072 op, 550589377.00 ns, 4.2007 us/op
+WorkloadWarmup 6: 131072 op, 549412549.00 ns, 4.1917 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 131072 op, 554435247.00 ns, 4.2300 us/op
+WorkloadActual 2: 131072 op, 547747679.00 ns, 4.1790 us/op
+WorkloadActual 3: 131072 op, 553327990.00 ns, 4.2216 us/op
+WorkloadActual 4: 131072 op, 559243556.00 ns, 4.2667 us/op
+WorkloadActual 5: 131072 op, 560554845.00 ns, 4.2767 us/op
+WorkloadActual 6: 131072 op, 561307144.00 ns, 4.2824 us/op
+WorkloadActual 7: 131072 op, 562451271.00 ns, 4.2912 us/op
+WorkloadActual 8: 131072 op, 549475844.00 ns, 4.1922 us/op
+WorkloadActual 9: 131072 op, 549777389.00 ns, 4.1945 us/op
+WorkloadActual 10: 131072 op, 548519854.00 ns, 4.1849 us/op
+WorkloadActual 11: 131072 op, 549903160.00 ns, 4.1954 us/op
+WorkloadActual 12: 131072 op, 548493752.00 ns, 4.1847 us/op
+WorkloadActual 13: 131072 op, 550881285.00 ns, 4.2029 us/op
+WorkloadActual 14: 131072 op, 549972588.00 ns, 4.1960 us/op
+WorkloadActual 15: 131072 op, 547478779.00 ns, 4.1769 us/op
+
+// AfterActualRun
+WorkloadResult 1: 131072 op, 553845084.00 ns, 4.2255 us/op
+WorkloadResult 2: 131072 op, 547157516.00 ns, 4.1745 us/op
+WorkloadResult 3: 131072 op, 552737827.00 ns, 4.2171 us/op
+WorkloadResult 4: 131072 op, 558653393.00 ns, 4.2622 us/op
+WorkloadResult 5: 131072 op, 559964682.00 ns, 4.2722 us/op
+WorkloadResult 6: 131072 op, 560716981.00 ns, 4.2779 us/op
+WorkloadResult 7: 131072 op, 561861108.00 ns, 4.2867 us/op
+WorkloadResult 8: 131072 op, 548885681.00 ns, 4.1877 us/op
+WorkloadResult 9: 131072 op, 549187226.00 ns, 4.1900 us/op
+WorkloadResult 10: 131072 op, 547929691.00 ns, 4.1804 us/op
+WorkloadResult 11: 131072 op, 549312997.00 ns, 4.1909 us/op
+WorkloadResult 12: 131072 op, 547903589.00 ns, 4.1802 us/op
+WorkloadResult 13: 131072 op, 550291122.00 ns, 4.1984 us/op
+WorkloadResult 14: 131072 op, 549382425.00 ns, 4.1915 us/op
+WorkloadResult 15: 131072 op, 546888616.00 ns, 4.1724 us/op
+// GC: 16 0 0 290455552 131072
+// Threading: 0 0 131072
+
+// AfterAll
+// Benchmark Process 383980 has exited with code 0.
+
+Mean = 4.214 μs, StdErr = 0.011 μs (0.25%), N = 15, StdDev = 0.041 μs
+Min = 4.172 μs, Q1 = 4.184 μs, Median = 4.191 μs, Q3 = 4.244 μs, Max = 4.287 μs
+IQR = 0.060 μs, LowerFence = 4.094 μs, UpperFence = 4.334 μs
+ConfidenceInterval = [4.170 μs; 4.257 μs] (CI 99.9%), Margin = 0.044 μs (1.04% of Mean)
+Skewness = 0.68, Kurtosis = 1.71, MValue = 2
+
+// ** Remained 4 (40.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:44 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Large_Ascii: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Large_Ascii --job Default --benchmarkId 6 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 311394.00 ns, 311.3940 us/op
+WorkloadJitting 1: 1 op, 9675822.00 ns, 9.6758 ms/op
+
+OverheadJitting 2: 16 op, 696105.00 ns, 43.5066 us/op
+WorkloadJitting 2: 16 op, 871885.00 ns, 54.4928 us/op
+
+WorkloadPilot 1: 16 op, 174731.00 ns, 10.9207 us/op
+WorkloadPilot 2: 32 op, 320218.00 ns, 10.0068 us/op
+WorkloadPilot 3: 64 op, 645882.00 ns, 10.0919 us/op
+WorkloadPilot 4: 128 op, 1262522.00 ns, 9.8635 us/op
+WorkloadPilot 5: 256 op, 2487541.00 ns, 9.7170 us/op
+WorkloadPilot 6: 512 op, 4986559.00 ns, 9.7394 us/op
+WorkloadPilot 7: 1024 op, 9893939.00 ns, 9.6620 us/op
+WorkloadPilot 8: 2048 op, 19700894.00 ns, 9.6196 us/op
+WorkloadPilot 9: 4096 op, 39679238.00 ns, 9.6873 us/op
+WorkloadPilot 10: 8192 op, 80443970.00 ns, 9.8198 us/op
+WorkloadPilot 11: 16384 op, 75620800.00 ns, 4.6155 us/op
+WorkloadPilot 12: 32768 op, 141702648.00 ns, 4.3244 us/op
+WorkloadPilot 13: 65536 op, 283276204.00 ns, 4.3225 us/op
+WorkloadPilot 14: 131072 op, 565874497.00 ns, 4.3173 us/op
+
+OverheadWarmup 1: 131072 op, 664940.00 ns, 5.0731 ns/op
+OverheadWarmup 2: 131072 op, 652774.00 ns, 4.9803 ns/op
+OverheadWarmup 3: 131072 op, 665096.00 ns, 5.0743 ns/op
+OverheadWarmup 4: 131072 op, 649767.00 ns, 4.9573 ns/op
+OverheadWarmup 5: 131072 op, 628292.00 ns, 4.7935 ns/op
+OverheadWarmup 6: 131072 op, 649203.00 ns, 4.9530 ns/op
+OverheadWarmup 7: 131072 op, 628056.00 ns, 4.7917 ns/op
+
+OverheadActual 1: 131072 op, 649809.00 ns, 4.9576 ns/op
+OverheadActual 2: 131072 op, 648044.00 ns, 4.9442 ns/op
+OverheadActual 3: 131072 op, 640443.00 ns, 4.8862 ns/op
+OverheadActual 4: 131072 op, 650199.00 ns, 4.9606 ns/op
+OverheadActual 5: 131072 op, 642785.00 ns, 4.9041 ns/op
+OverheadActual 6: 131072 op, 652547.00 ns, 4.9785 ns/op
+OverheadActual 7: 131072 op, 627517.00 ns, 4.7876 ns/op
+OverheadActual 8: 131072 op, 648999.00 ns, 4.9515 ns/op
+OverheadActual 9: 131072 op, 628466.00 ns, 4.7948 ns/op
+OverheadActual 10: 131072 op, 659454.00 ns, 5.0312 ns/op
+OverheadActual 11: 131072 op, 635259.00 ns, 4.8466 ns/op
+OverheadActual 12: 131072 op, 644041.00 ns, 4.9136 ns/op
+OverheadActual 13: 131072 op, 643856.00 ns, 4.9122 ns/op
+OverheadActual 14: 131072 op, 627704.00 ns, 4.7890 ns/op
+OverheadActual 15: 131072 op, 648829.00 ns, 4.9502 ns/op
+
+WorkloadWarmup 1: 131072 op, 566631515.00 ns, 4.3231 us/op
+WorkloadWarmup 2: 131072 op, 568815006.00 ns, 4.3397 us/op
+WorkloadWarmup 3: 131072 op, 568972520.00 ns, 4.3409 us/op
+WorkloadWarmup 4: 131072 op, 568821255.00 ns, 4.3398 us/op
+WorkloadWarmup 5: 131072 op, 565746764.00 ns, 4.3163 us/op
+WorkloadWarmup 6: 131072 op, 567042433.00 ns, 4.3262 us/op
+WorkloadWarmup 7: 131072 op, 567446206.00 ns, 4.3293 us/op
+WorkloadWarmup 8: 131072 op, 566514755.00 ns, 4.3222 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 131072 op, 567101972.00 ns, 4.3266 us/op
+WorkloadActual 2: 131072 op, 566521227.00 ns, 4.3222 us/op
+WorkloadActual 3: 131072 op, 568914859.00 ns, 4.3405 us/op
+WorkloadActual 4: 131072 op, 567875068.00 ns, 4.3325 us/op
+WorkloadActual 5: 131072 op, 566884223.00 ns, 4.3250 us/op
+WorkloadActual 6: 131072 op, 564647048.00 ns, 4.3079 us/op
+WorkloadActual 7: 131072 op, 564899373.00 ns, 4.3098 us/op
+WorkloadActual 8: 131072 op, 567098739.00 ns, 4.3266 us/op
+WorkloadActual 9: 131072 op, 564527537.00 ns, 4.3070 us/op
+WorkloadActual 10: 131072 op, 567569074.00 ns, 4.3302 us/op
+WorkloadActual 11: 131072 op, 567168408.00 ns, 4.3272 us/op
+WorkloadActual 12: 131072 op, 572986269.00 ns, 4.3715 us/op
+WorkloadActual 13: 131072 op, 570113710.00 ns, 4.3496 us/op
+WorkloadActual 14: 131072 op, 573522585.00 ns, 4.3756 us/op
+WorkloadActual 15: 131072 op, 576045726.00 ns, 4.3949 us/op
+
+// AfterActualRun
+WorkloadResult 1: 131072 op, 566457931.00 ns, 4.3217 us/op
+WorkloadResult 2: 131072 op, 565877186.00 ns, 4.3173 us/op
+WorkloadResult 3: 131072 op, 568270818.00 ns, 4.3356 us/op
+WorkloadResult 4: 131072 op, 567231027.00 ns, 4.3276 us/op
+WorkloadResult 5: 131072 op, 566240182.00 ns, 4.3201 us/op
+WorkloadResult 6: 131072 op, 564003007.00 ns, 4.3030 us/op
+WorkloadResult 7: 131072 op, 564255332.00 ns, 4.3049 us/op
+WorkloadResult 8: 131072 op, 566454698.00 ns, 4.3217 us/op
+WorkloadResult 9: 131072 op, 563883496.00 ns, 4.3021 us/op
+WorkloadResult 10: 131072 op, 566925033.00 ns, 4.3253 us/op
+WorkloadResult 11: 131072 op, 566524367.00 ns, 4.3222 us/op
+WorkloadResult 12: 131072 op, 572342228.00 ns, 4.3666 us/op
+WorkloadResult 13: 131072 op, 569469669.00 ns, 4.3447 us/op
+WorkloadResult 14: 131072 op, 572878544.00 ns, 4.3707 us/op
+// GC: 0 0 0 0 131072
+// Threading: 0 0 131072
+
+// AfterAll
+// Benchmark Process 384027 has exited with code 0.
+
+Mean = 4.327 μs, StdErr = 0.006 μs (0.13%), N = 14, StdDev = 0.021 μs
+Min = 4.302 μs, Q1 = 4.318 μs, Median = 4.322 μs, Q3 = 4.334 μs, Max = 4.371 μs
+IQR = 0.016 μs, LowerFence = 4.295 μs, UpperFence = 4.357 μs
+ConfidenceInterval = [4.304 μs; 4.351 μs] (CI 99.9%), Margin = 0.024 μs (0.55% of Mean)
+Skewness = 0.79, Kurtosis = 2.54, MValue = 2
+
+// ** Remained 3 (30.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:44 (0h 1m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Large_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Large_Mixed --job Default --benchmarkId 7 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 271388.00 ns, 271.3880 us/op
+WorkloadJitting 1: 1 op, 19615436.00 ns, 19.6154 ms/op
+
+OverheadJitting 2: 16 op, 676444.00 ns, 42.2778 us/op
+WorkloadJitting 2: 16 op, 27170849.00 ns, 1.6982 ms/op
+
+WorkloadPilot 1: 16 op, 26208795.00 ns, 1.6380 ms/op
+WorkloadPilot 2: 32 op, 53223642.00 ns, 1.6632 ms/op
+WorkloadPilot 3: 64 op, 104765857.00 ns, 1.6370 ms/op
+WorkloadPilot 4: 128 op, 139959463.00 ns, 1.0934 ms/op
+WorkloadPilot 5: 256 op, 200869422.00 ns, 784.6462 us/op
+WorkloadPilot 6: 512 op, 403225678.00 ns, 787.5502 us/op
+WorkloadPilot 7: 1024 op, 804757860.00 ns, 785.8963 us/op
+
+OverheadWarmup 1: 1024 op, 7597.00 ns, 7.4189 ns/op
+OverheadWarmup 2: 1024 op, 10177.00 ns, 9.9385 ns/op
+OverheadWarmup 3: 1024 op, 5670.00 ns, 5.5371 ns/op
+OverheadWarmup 4: 1024 op, 5609.00 ns, 5.4775 ns/op
+OverheadWarmup 5: 1024 op, 5965.00 ns, 5.8252 ns/op
+OverheadWarmup 6: 1024 op, 5854.00 ns, 5.7168 ns/op
+
+OverheadActual 1: 1024 op, 5792.00 ns, 5.6563 ns/op
+OverheadActual 2: 1024 op, 6046.00 ns, 5.9043 ns/op
+OverheadActual 3: 1024 op, 5943.00 ns, 5.8037 ns/op
+OverheadActual 4: 1024 op, 5875.00 ns, 5.7373 ns/op
+OverheadActual 5: 1024 op, 5918.00 ns, 5.7793 ns/op
+OverheadActual 6: 1024 op, 5724.00 ns, 5.5898 ns/op
+OverheadActual 7: 1024 op, 5700.00 ns, 5.5664 ns/op
+OverheadActual 8: 1024 op, 5675.00 ns, 5.5420 ns/op
+OverheadActual 9: 1024 op, 5717.00 ns, 5.5830 ns/op
+OverheadActual 10: 1024 op, 5604.00 ns, 5.4727 ns/op
+OverheadActual 11: 1024 op, 5661.00 ns, 5.5283 ns/op
+OverheadActual 12: 1024 op, 5678.00 ns, 5.5449 ns/op
+OverheadActual 13: 1024 op, 5728.00 ns, 5.5938 ns/op
+OverheadActual 14: 1024 op, 5668.00 ns, 5.5352 ns/op
+OverheadActual 15: 1024 op, 5721.00 ns, 5.5869 ns/op
+
+WorkloadWarmup 1: 1024 op, 827006263.00 ns, 807.6233 us/op
+WorkloadWarmup 2: 1024 op, 802954557.00 ns, 784.1353 us/op
+WorkloadWarmup 3: 1024 op, 801530265.00 ns, 782.7444 us/op
+WorkloadWarmup 4: 1024 op, 800263235.00 ns, 781.5071 us/op
+WorkloadWarmup 5: 1024 op, 802227203.00 ns, 783.4250 us/op
+WorkloadWarmup 6: 1024 op, 801785670.00 ns, 782.9938 us/op
+WorkloadWarmup 7: 1024 op, 804611916.00 ns, 785.7538 us/op
+WorkloadWarmup 8: 1024 op, 799745797.00 ns, 781.0018 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 1024 op, 808443550.00 ns, 789.4957 us/op
+WorkloadActual 2: 1024 op, 806366769.00 ns, 787.4675 us/op
+WorkloadActual 3: 1024 op, 804320587.00 ns, 785.4693 us/op
+WorkloadActual 4: 1024 op, 814205352.00 ns, 795.1224 us/op
+WorkloadActual 5: 1024 op, 808236944.00 ns, 789.2939 us/op
+WorkloadActual 6: 1024 op, 812469142.00 ns, 793.4269 us/op
+WorkloadActual 7: 1024 op, 813417491.00 ns, 794.3530 us/op
+WorkloadActual 8: 1024 op, 814684162.00 ns, 795.5900 us/op
+WorkloadActual 9: 1024 op, 813488206.00 ns, 794.4221 us/op
+WorkloadActual 10: 1024 op, 803821850.00 ns, 784.9823 us/op
+WorkloadActual 11: 1024 op, 816380485.00 ns, 797.2466 us/op
+WorkloadActual 12: 1024 op, 814548518.00 ns, 795.4575 us/op
+WorkloadActual 13: 1024 op, 812751033.00 ns, 793.7022 us/op
+WorkloadActual 14: 1024 op, 810633666.00 ns, 791.6344 us/op
+WorkloadActual 15: 1024 op, 802600956.00 ns, 783.7900 us/op
+
+// AfterActualRun
+WorkloadResult 1: 1024 op, 808437829.00 ns, 789.4901 us/op
+WorkloadResult 2: 1024 op, 806361048.00 ns, 787.4620 us/op
+WorkloadResult 3: 1024 op, 804314866.00 ns, 785.4637 us/op
+WorkloadResult 4: 1024 op, 814199631.00 ns, 795.1168 us/op
+WorkloadResult 5: 1024 op, 808231223.00 ns, 789.2883 us/op
+WorkloadResult 6: 1024 op, 812463421.00 ns, 793.4213 us/op
+WorkloadResult 7: 1024 op, 813411770.00 ns, 794.3474 us/op
+WorkloadResult 8: 1024 op, 814678441.00 ns, 795.5844 us/op
+WorkloadResult 9: 1024 op, 813482485.00 ns, 794.4165 us/op
+WorkloadResult 10: 1024 op, 803816129.00 ns, 784.9767 us/op
+WorkloadResult 11: 1024 op, 816374764.00 ns, 797.2410 us/op
+WorkloadResult 12: 1024 op, 814542797.00 ns, 795.4520 us/op
+WorkloadResult 13: 1024 op, 812745312.00 ns, 793.6966 us/op
+WorkloadResult 14: 1024 op, 810627945.00 ns, 791.6289 us/op
+WorkloadResult 15: 1024 op, 802595235.00 ns, 783.7844 us/op
+// GC: 59 59 59 226156912 1024
+// Threading: 0 0 1024
+
+// AfterAll
+// Benchmark Process 384111 has exited with code 0.
+
+Mean = 791.425 μs, StdErr = 1.128 μs (0.14%), N = 15, StdDev = 4.368 μs
+Min = 783.784 μs, Q1 = 788.375 μs, Median = 793.421 μs, Q3 = 794.767 μs, Max = 797.241 μs
+IQR = 6.392 μs, LowerFence = 778.788 μs, UpperFence = 804.354 μs
+ConfidenceInterval = [786.755 μs; 796.095 μs] (CI 99.9%), Margin = 4.670 μs (0.59% of Mean)
+Skewness = -0.44, Kurtosis = 1.61, MValue = 2
+
+// ** Remained 2 (20.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:44 (0h 0m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Large_WorstCase: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Large_WorstCase --job Default --benchmarkId 8 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 348269.00 ns, 348.2690 us/op
+WorkloadJitting 1: 1 op, 24693917.00 ns, 24.6939 ms/op
+
+OverheadJitting 2: 16 op, 724514.00 ns, 45.2821 us/op
+WorkloadJitting 2: 16 op, 117451208.00 ns, 7.3407 ms/op
+
+WorkloadPilot 1: 16 op, 116836942.00 ns, 7.3023 ms/op
+WorkloadPilot 2: 32 op, 154538088.00 ns, 4.8293 ms/op
+WorkloadPilot 3: 64 op, 148586840.00 ns, 2.3217 ms/op
+WorkloadPilot 4: 128 op, 279166095.00 ns, 2.1810 ms/op
+WorkloadPilot 5: 256 op, 560424889.00 ns, 2.1892 ms/op
+
+OverheadWarmup 1: 256 op, 5119.00 ns, 19.9961 ns/op
+OverheadWarmup 2: 256 op, 3564.00 ns, 13.9219 ns/op
+OverheadWarmup 3: 256 op, 3313.00 ns, 12.9414 ns/op
+OverheadWarmup 4: 256 op, 3369.00 ns, 13.1602 ns/op
+OverheadWarmup 5: 256 op, 3276.00 ns, 12.7969 ns/op
+OverheadWarmup 6: 256 op, 3195.00 ns, 12.4805 ns/op
+OverheadWarmup 7: 256 op, 3219.00 ns, 12.5742 ns/op
+OverheadWarmup 8: 256 op, 3266.00 ns, 12.7578 ns/op
+OverheadWarmup 9: 256 op, 3597.00 ns, 14.0508 ns/op
+OverheadWarmup 10: 256 op, 3486.00 ns, 13.6172 ns/op
+
+OverheadActual 1: 256 op, 2174.00 ns, 8.4922 ns/op
+OverheadActual 2: 256 op, 2150.00 ns, 8.3984 ns/op
+OverheadActual 3: 256 op, 2119.00 ns, 8.2773 ns/op
+OverheadActual 4: 256 op, 1854.00 ns, 7.2422 ns/op
+OverheadActual 5: 256 op, 2057.00 ns, 8.0352 ns/op
+OverheadActual 6: 256 op, 1933.00 ns, 7.5508 ns/op
+OverheadActual 7: 256 op, 2085.00 ns, 8.1445 ns/op
+OverheadActual 8: 256 op, 2537.00 ns, 9.9102 ns/op
+OverheadActual 9: 256 op, 1875.00 ns, 7.3242 ns/op
+OverheadActual 10: 256 op, 1981.00 ns, 7.7383 ns/op
+OverheadActual 11: 256 op, 1982.00 ns, 7.7422 ns/op
+OverheadActual 12: 256 op, 1806.00 ns, 7.0547 ns/op
+OverheadActual 13: 256 op, 1911.00 ns, 7.4648 ns/op
+OverheadActual 14: 256 op, 1902.00 ns, 7.4297 ns/op
+OverheadActual 15: 256 op, 1986.00 ns, 7.7578 ns/op
+OverheadActual 16: 256 op, 1881.00 ns, 7.3477 ns/op
+OverheadActual 17: 256 op, 1943.00 ns, 7.5898 ns/op
+OverheadActual 18: 256 op, 1956.00 ns, 7.6406 ns/op
+OverheadActual 19: 256 op, 1995.00 ns, 7.7930 ns/op
+
+WorkloadWarmup 1: 256 op, 586948834.00 ns, 2.2928 ms/op
+WorkloadWarmup 2: 256 op, 570368334.00 ns, 2.2280 ms/op
+WorkloadWarmup 3: 256 op, 576779065.00 ns, 2.2530 ms/op
+WorkloadWarmup 4: 256 op, 572135577.00 ns, 2.2349 ms/op
+WorkloadWarmup 5: 256 op, 574155063.00 ns, 2.2428 ms/op
+WorkloadWarmup 6: 256 op, 572209015.00 ns, 2.2352 ms/op
+
+// BeforeActualRun
+WorkloadActual 1: 256 op, 572342949.00 ns, 2.2357 ms/op
+WorkloadActual 2: 256 op, 590654492.00 ns, 2.3072 ms/op
+WorkloadActual 3: 256 op, 587646018.00 ns, 2.2955 ms/op
+WorkloadActual 4: 256 op, 590117631.00 ns, 2.3051 ms/op
+WorkloadActual 5: 256 op, 592562645.00 ns, 2.3147 ms/op
+WorkloadActual 6: 256 op, 584881765.00 ns, 2.2847 ms/op
+WorkloadActual 7: 256 op, 585708102.00 ns, 2.2879 ms/op
+WorkloadActual 8: 256 op, 589676979.00 ns, 2.3034 ms/op
+WorkloadActual 9: 256 op, 580983431.00 ns, 2.2695 ms/op
+WorkloadActual 10: 256 op, 577385842.00 ns, 2.2554 ms/op
+WorkloadActual 11: 256 op, 578312295.00 ns, 2.2590 ms/op
+WorkloadActual 12: 256 op, 578390114.00 ns, 2.2593 ms/op
+WorkloadActual 13: 256 op, 575169136.00 ns, 2.2468 ms/op
+WorkloadActual 14: 256 op, 582116813.00 ns, 2.2739 ms/op
+WorkloadActual 15: 256 op, 573613634.00 ns, 2.2407 ms/op
+
+// AfterActualRun
+WorkloadResult 1: 256 op, 572340968.00 ns, 2.2357 ms/op
+WorkloadResult 2: 256 op, 590652511.00 ns, 2.3072 ms/op
+WorkloadResult 3: 256 op, 587644037.00 ns, 2.2955 ms/op
+WorkloadResult 4: 256 op, 590115650.00 ns, 2.3051 ms/op
+WorkloadResult 5: 256 op, 592560664.00 ns, 2.3147 ms/op
+WorkloadResult 6: 256 op, 584879784.00 ns, 2.2847 ms/op
+WorkloadResult 7: 256 op, 585706121.00 ns, 2.2879 ms/op
+WorkloadResult 8: 256 op, 589674998.00 ns, 2.3034 ms/op
+WorkloadResult 9: 256 op, 580981450.00 ns, 2.2695 ms/op
+WorkloadResult 10: 256 op, 577383861.00 ns, 2.2554 ms/op
+WorkloadResult 11: 256 op, 578310314.00 ns, 2.2590 ms/op
+WorkloadResult 12: 256 op, 578388133.00 ns, 2.2593 ms/op
+WorkloadResult 13: 256 op, 575167155.00 ns, 2.2467 ms/op
+WorkloadResult 14: 256 op, 582114832.00 ns, 2.2739 ms/op
+WorkloadResult 15: 256 op, 573611653.00 ns, 2.2407 ms/op
+// GC: 27 27 27 104899384 256
+// Threading: 0 0 256
+
+// AfterAll
+// Benchmark Process 384205 has exited with code 0.
+
+Mean = 2.276 ms, StdErr = 0.007 ms (0.29%), N = 15, StdDev = 0.026 ms
+Min = 2.236 ms, Q1 = 2.257 ms, Median = 2.274 ms, Q3 = 2.299 ms, Max = 2.315 ms
+IQR = 0.042 ms, LowerFence = 2.194 ms, UpperFence = 2.363 ms
+ConfidenceInterval = [2.248 ms; 2.304 ms] (CI 99.9%), Margin = 0.028 ms (1.22% of Mean)
+Skewness = -0.03, Kurtosis = 1.46, MValue = 2
+
+// ** Remained 1 (10.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:44 (0h 0m from now) **
+// **************************
+// Benchmark: Utf8ToAsciiConverterBenchmarks.Span_Medium_Mixed: DefaultJob
+// *** Execute ***
+// Launch: 1 / 1
+// Execute: dotnet Umbraco.Tests.Benchmarks-DefaultJob-1.dll --anonymousPipes 123 124 --benchmarkName Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks.Span_Medium_Mixed --job Default --benchmarkId 9 in /home/yv01p/Umbraco-CMS/tests/Umbraco.Tests.Benchmarks/bin/Release/net10.0/Umbraco.Tests.Benchmarks-DefaultJob-1/bin/Release/net10.0
+// Failed to set up high priority (Permission denied). In order to run benchmarks with high priority, make sure you have the right permissions.
+// BeforeAnythingElse
+
+// Benchmark Process Environment Information:
+// BenchmarkDotNet v0.15.6
+// Runtime=.NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+// GC=Concurrent Workstation
+// HardwareIntrinsics=AVX512 F+BW+CD+DQ+VL,AVX2+BMI1+BMI2+F16C+FMA+LZCNT+MOVBE,AVX,SSE3+SSSE3+SSE4.1+SSE4.2+POPCNT,X86Base+SSE+SSE2,AES+PCLMUL VectorSize=256
+// Job: DefaultJob
+
+OverheadJitting 1: 1 op, 247533.00 ns, 247.5330 us/op
+WorkloadJitting 1: 1 op, 11741034.00 ns, 11.7410 ms/op
+
+OverheadJitting 2: 16 op, 475205.00 ns, 29.7003 us/op
+WorkloadJitting 2: 16 op, 953815.00 ns, 59.6134 us/op
+
+WorkloadPilot 1: 16 op, 436166.00 ns, 27.2604 us/op
+WorkloadPilot 2: 32 op, 802313.00 ns, 25.0723 us/op
+WorkloadPilot 3: 64 op, 1611127.00 ns, 25.1739 us/op
+WorkloadPilot 4: 128 op, 3070358.00 ns, 23.9872 us/op
+WorkloadPilot 5: 256 op, 6042237.00 ns, 23.6025 us/op
+WorkloadPilot 6: 512 op, 11663651.00 ns, 22.7806 us/op
+WorkloadPilot 7: 1024 op, 23183573.00 ns, 22.6402 us/op
+WorkloadPilot 8: 2048 op, 46111072.00 ns, 22.5152 us/op
+WorkloadPilot 9: 4096 op, 93750054.00 ns, 22.8882 us/op
+WorkloadPilot 10: 8192 op, 35062196.00 ns, 4.2801 us/op
+WorkloadPilot 11: 16384 op, 61903080.00 ns, 3.7783 us/op
+WorkloadPilot 12: 32768 op, 123970175.00 ns, 3.7833 us/op
+WorkloadPilot 13: 65536 op, 249212757.00 ns, 3.8027 us/op
+WorkloadPilot 14: 131072 op, 498932115.00 ns, 3.8065 us/op
+WorkloadPilot 15: 262144 op, 1009777897.00 ns, 3.8520 us/op
+
+OverheadWarmup 1: 262144 op, 764235.00 ns, 2.9153 ns/op
+OverheadWarmup 2: 262144 op, 767327.00 ns, 2.9271 ns/op
+OverheadWarmup 3: 262144 op, 769045.00 ns, 2.9337 ns/op
+OverheadWarmup 4: 262144 op, 769400.00 ns, 2.9350 ns/op
+OverheadWarmup 5: 262144 op, 761727.00 ns, 2.9058 ns/op
+OverheadWarmup 6: 262144 op, 753156.00 ns, 2.8731 ns/op
+OverheadWarmup 7: 262144 op, 742948.00 ns, 2.8341 ns/op
+OverheadWarmup 8: 262144 op, 740298.00 ns, 2.8240 ns/op
+OverheadWarmup 9: 262144 op, 758627.00 ns, 2.8939 ns/op
+OverheadWarmup 10: 262144 op, 765697.00 ns, 2.9209 ns/op
+
+OverheadActual 1: 262144 op, 759145.00 ns, 2.8959 ns/op
+OverheadActual 2: 262144 op, 741796.00 ns, 2.8297 ns/op
+OverheadActual 3: 262144 op, 749939.00 ns, 2.8608 ns/op
+OverheadActual 4: 262144 op, 778638.00 ns, 2.9703 ns/op
+OverheadActual 5: 262144 op, 757683.00 ns, 2.8903 ns/op
+OverheadActual 6: 262144 op, 782692.00 ns, 2.9857 ns/op
+OverheadActual 7: 262144 op, 746148.00 ns, 2.8463 ns/op
+OverheadActual 8: 262144 op, 784157.00 ns, 2.9913 ns/op
+OverheadActual 9: 262144 op, 770008.00 ns, 2.9373 ns/op
+OverheadActual 10: 262144 op, 762881.00 ns, 2.9102 ns/op
+OverheadActual 11: 262144 op, 903022.00 ns, 3.4448 ns/op
+OverheadActual 12: 262144 op, 741416.00 ns, 2.8283 ns/op
+OverheadActual 13: 262144 op, 759247.00 ns, 2.8963 ns/op
+OverheadActual 14: 262144 op, 765653.00 ns, 2.9207 ns/op
+OverheadActual 15: 262144 op, 749871.00 ns, 2.8605 ns/op
+
+WorkloadWarmup 1: 262144 op, 1007345702.00 ns, 3.8427 us/op
+WorkloadWarmup 2: 262144 op, 1011775762.00 ns, 3.8596 us/op
+WorkloadWarmup 3: 262144 op, 996506874.00 ns, 3.8014 us/op
+WorkloadWarmup 4: 262144 op, 997609214.00 ns, 3.8056 us/op
+WorkloadWarmup 5: 262144 op, 993312829.00 ns, 3.7892 us/op
+WorkloadWarmup 6: 262144 op, 981643109.00 ns, 3.7447 us/op
+
+// BeforeActualRun
+WorkloadActual 1: 262144 op, 982983627.00 ns, 3.7498 us/op
+WorkloadActual 2: 262144 op, 982267036.00 ns, 3.7471 us/op
+WorkloadActual 3: 262144 op, 980147610.00 ns, 3.7390 us/op
+WorkloadActual 4: 262144 op, 983000281.00 ns, 3.7498 us/op
+WorkloadActual 5: 262144 op, 981699095.00 ns, 3.7449 us/op
+WorkloadActual 6: 262144 op, 980439018.00 ns, 3.7401 us/op
+WorkloadActual 7: 262144 op, 980492937.00 ns, 3.7403 us/op
+WorkloadActual 8: 262144 op, 986145390.00 ns, 3.7618 us/op
+WorkloadActual 9: 262144 op, 982640540.00 ns, 3.7485 us/op
+WorkloadActual 10: 262144 op, 986257490.00 ns, 3.7623 us/op
+WorkloadActual 11: 262144 op, 981490923.00 ns, 3.7441 us/op
+WorkloadActual 12: 262144 op, 980770165.00 ns, 3.7413 us/op
+WorkloadActual 13: 262144 op, 980028778.00 ns, 3.7385 us/op
+WorkloadActual 14: 262144 op, 982176800.00 ns, 3.7467 us/op
+WorkloadActual 15: 262144 op, 1004036736.00 ns, 3.8301 us/op
+
+// AfterActualRun
+WorkloadResult 1: 262144 op, 982224380.00 ns, 3.7469 us/op
+WorkloadResult 2: 262144 op, 981507789.00 ns, 3.7442 us/op
+WorkloadResult 3: 262144 op, 979388363.00 ns, 3.7361 us/op
+WorkloadResult 4: 262144 op, 982241034.00 ns, 3.7470 us/op
+WorkloadResult 5: 262144 op, 980939848.00 ns, 3.7420 us/op
+WorkloadResult 6: 262144 op, 979679771.00 ns, 3.7372 us/op
+WorkloadResult 7: 262144 op, 979733690.00 ns, 3.7374 us/op
+WorkloadResult 8: 262144 op, 985386143.00 ns, 3.7589 us/op
+WorkloadResult 9: 262144 op, 981881293.00 ns, 3.7456 us/op
+WorkloadResult 10: 262144 op, 985498243.00 ns, 3.7594 us/op
+WorkloadResult 11: 262144 op, 980731676.00 ns, 3.7412 us/op
+WorkloadResult 12: 262144 op, 980010918.00 ns, 3.7384 us/op
+WorkloadResult 13: 262144 op, 979269531.00 ns, 3.7356 us/op
+WorkloadResult 14: 262144 op, 981417553.00 ns, 3.7438 us/op
+// GC: 1 0 0 31457280 262144
+// Threading: 0 0 262144
+
+// AfterAll
+// Benchmark Process 384252 has exited with code 0.
+
+Mean = 3.744 μs, StdErr = 0.002 μs (0.05%), N = 14, StdDev = 0.008 μs
+Min = 3.736 μs, Q1 = 3.738 μs, Median = 3.743 μs, Q3 = 3.747 μs, Max = 3.759 μs
+IQR = 0.009 μs, LowerFence = 3.724 μs, UpperFence = 3.760 μs
+ConfidenceInterval = [3.735 μs; 3.752 μs] (CI 99.9%), Margin = 0.009 μs (0.23% of Mean)
+Skewness = 0.91, Kurtosis = 2.69, MValue = 2
+
+// ** Remained 0 (0.0 %) benchmark(s) to run. Estimated finish 2025-12-13 3:44 (0h 0m from now) **
+// ***** BenchmarkRunner: Finish *****
+
+// * Export *
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.csv
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-github.md
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.html
+ BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-default.md
+
+// * Detailed results *
+Utf8ToAsciiConverterBenchmarks.Tiny_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 6.756 ns, StdErr = 0.025 ns (0.37%), N = 15, StdDev = 0.097 ns
+Min = 6.657 ns, Q1 = 6.691 ns, Median = 6.709 ns, Q3 = 6.829 ns, Max = 6.938 ns
+IQR = 0.137 ns, LowerFence = 6.485 ns, UpperFence = 7.035 ns
+ConfidenceInterval = [6.652 ns; 6.861 ns] (CI 99.9%), Margin = 0.104 ns (1.54% of Mean)
+Skewness = 0.81, Kurtosis = 1.83, MValue = 2
+-------------------- Histogram --------------------
+[6.621 ns ; 6.978 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Tiny_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 6.554 ns, StdErr = 0.004 ns (0.06%), N = 15, StdDev = 0.014 ns
+Min = 6.530 ns, Q1 = 6.544 ns, Median = 6.555 ns, Q3 = 6.564 ns, Max = 6.579 ns
+IQR = 0.020 ns, LowerFence = 6.513 ns, UpperFence = 6.595 ns
+ConfidenceInterval = [6.539 ns; 6.570 ns] (CI 99.9%), Margin = 0.015 ns (0.23% of Mean)
+Skewness = 0.02, Kurtosis = 1.78, MValue = 2
+-------------------- Histogram --------------------
+[6.523 ns ; 6.587 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Small_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 8.132 ns, StdErr = 0.007 ns (0.08%), N = 15, StdDev = 0.025 ns
+Min = 8.096 ns, Q1 = 8.109 ns, Median = 8.138 ns, Q3 = 8.149 ns, Max = 8.179 ns
+IQR = 0.040 ns, LowerFence = 8.049 ns, UpperFence = 8.208 ns
+ConfidenceInterval = [8.105 ns; 8.159 ns] (CI 99.9%), Margin = 0.027 ns (0.33% of Mean)
+Skewness = 0.08, Kurtosis = 1.76, MValue = 2
+-------------------- Histogram --------------------
+[8.082 ns ; 8.193 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Small_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 308.895 ns, StdErr = 0.168 ns (0.05%), N = 15, StdDev = 0.652 ns
+Min = 307.974 ns, Q1 = 308.358 ns, Median = 308.916 ns, Q3 = 309.359 ns, Max = 310.130 ns
+IQR = 1.001 ns, LowerFence = 306.856 ns, UpperFence = 310.861 ns
+ConfidenceInterval = [308.197 ns; 309.592 ns] (CI 99.9%), Margin = 0.698 ns (0.23% of Mean)
+Skewness = 0.2, Kurtosis = 1.83, MValue = 2
+-------------------- Histogram --------------------
+[307.626 ns ; 310.477 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Medium_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 38.200 ns, StdErr = 0.051 ns (0.13%), N = 15, StdDev = 0.197 ns
+Min = 37.893 ns, Q1 = 38.074 ns, Median = 38.193 ns, Q3 = 38.332 ns, Max = 38.543 ns
+IQR = 0.258 ns, LowerFence = 37.686 ns, UpperFence = 38.720 ns
+ConfidenceInterval = [37.989 ns; 38.410 ns] (CI 99.9%), Margin = 0.210 ns (0.55% of Mean)
+Skewness = 0.31, Kurtosis = 1.81, MValue = 2
+-------------------- Histogram --------------------
+[37.788 ns ; 38.648 ns) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Medium_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 4.214 μs, StdErr = 0.011 μs (0.25%), N = 15, StdDev = 0.041 μs
+Min = 4.172 μs, Q1 = 4.184 μs, Median = 4.191 μs, Q3 = 4.244 μs, Max = 4.287 μs
+IQR = 0.060 μs, LowerFence = 4.094 μs, UpperFence = 4.334 μs
+ConfidenceInterval = [4.170 μs; 4.257 μs] (CI 99.9%), Margin = 0.044 μs (1.04% of Mean)
+Skewness = 0.68, Kurtosis = 1.71, MValue = 2
+-------------------- Histogram --------------------
+[4.151 μs ; 4.308 μs) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Large_Ascii: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 4.327 μs, StdErr = 0.006 μs (0.13%), N = 14, StdDev = 0.021 μs
+Min = 4.302 μs, Q1 = 4.318 μs, Median = 4.322 μs, Q3 = 4.334 μs, Max = 4.371 μs
+IQR = 0.016 μs, LowerFence = 4.295 μs, UpperFence = 4.357 μs
+ConfidenceInterval = [4.304 μs; 4.351 μs] (CI 99.9%), Margin = 0.024 μs (0.55% of Mean)
+Skewness = 0.79, Kurtosis = 2.54, MValue = 2
+-------------------- Histogram --------------------
+[4.291 μs ; 4.382 μs) | @@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Large_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 791.425 μs, StdErr = 1.128 μs (0.14%), N = 15, StdDev = 4.368 μs
+Min = 783.784 μs, Q1 = 788.375 μs, Median = 793.421 μs, Q3 = 794.767 μs, Max = 797.241 μs
+IQR = 6.392 μs, LowerFence = 778.788 μs, UpperFence = 804.354 μs
+ConfidenceInterval = [786.755 μs; 796.095 μs] (CI 99.9%), Margin = 4.670 μs (0.59% of Mean)
+Skewness = -0.44, Kurtosis = 1.61, MValue = 2
+-------------------- Histogram --------------------
+[781.460 μs ; 799.566 μs) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Large_WorstCase: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 2.276 ms, StdErr = 0.007 ms (0.29%), N = 15, StdDev = 0.026 ms
+Min = 2.236 ms, Q1 = 2.257 ms, Median = 2.274 ms, Q3 = 2.299 ms, Max = 2.315 ms
+IQR = 0.042 ms, LowerFence = 2.194 ms, UpperFence = 2.363 ms
+ConfidenceInterval = [2.248 ms; 2.304 ms] (CI 99.9%), Margin = 0.028 ms (1.22% of Mean)
+Skewness = -0.03, Kurtosis = 1.46, MValue = 2
+-------------------- Histogram --------------------
+[2.225 ms ; 2.319 ms) | @@@@@@@@@@@@@@@
+---------------------------------------------------
+
+Utf8ToAsciiConverterBenchmarks.Span_Medium_Mixed: DefaultJob
+Runtime = .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4; GC = Concurrent Workstation
+Mean = 3.744 μs, StdErr = 0.002 μs (0.05%), N = 14, StdDev = 0.008 μs
+Min = 3.736 μs, Q1 = 3.738 μs, Median = 3.743 μs, Q3 = 3.747 μs, Max = 3.759 μs
+IQR = 0.009 μs, LowerFence = 3.724 μs, UpperFence = 3.760 μs
+ConfidenceInterval = [3.735 μs; 3.752 μs] (CI 99.9%), Margin = 0.009 μs (0.23% of Mean)
+Skewness = 0.91, Kurtosis = 2.69, MValue = 2
+-------------------- Histogram --------------------
+[3.731 μs ; 3.764 μs) | @@@@@@@@@@@@@@
+---------------------------------------------------
+
+// * Summary *
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+|------------------ |-----------------:|---------------:|---------------:|-----:|---------:|---------:|---------:|----------:|
+| Tiny_Ascii | 6.756 ns | 0.1042 ns | 0.0974 ns | 1 | - | - | - | - |
+| Tiny_Mixed | 6.554 ns | 0.0153 ns | 0.0143 ns | 1 | - | - | - | - |
+| Small_Ascii | 8.132 ns | 0.0271 ns | 0.0253 ns | 2 | - | - | - | - |
+| Small_Mixed | 308.895 ns | 0.6975 ns | 0.6525 ns | 4 | 0.0129 | - | - | 224 B |
+| Medium_Ascii | 38.200 ns | 0.2104 ns | 0.1968 ns | 3 | - | - | - | - |
+| Medium_Mixed | 4,213.825 ns | 43.6474 ns | 40.8278 ns | 6 | 0.1221 | - | - | 2216 B |
+| Large_Ascii | 4,327.400 ns | 23.7729 ns | 21.0740 ns | 6 | - | - | - | - |
+| Large_Mixed | 791,424.668 ns | 4,670.0767 ns | 4,368.3927 ns | 7 | 57.6172 | 57.6172 | 57.6172 | 220856 B |
+| Large_WorstCase | 2,275,919.826 ns | 27,753.5138 ns | 25,960.6540 ns | 8 | 105.4688 | 105.4688 | 105.4688 | 409763 B |
+| Span_Medium_Mixed | 3,743.828 ns | 8.5415 ns | 7.5718 ns | 5 | 0.0038 | - | - | 120 B |
+
+// * Hints *
+Outliers
+ Utf8ToAsciiConverterBenchmarks.Large_Ascii: Default -> 1 outlier was removed (4.39 μs)
+ Utf8ToAsciiConverterBenchmarks.Span_Medium_Mixed: Default -> 1 outlier was removed (3.83 μs)
+
+// * Legends *
+ Mean : Arithmetic mean of all measurements
+ Error : Half of 99.9% confidence interval
+ StdDev : Standard deviation of all measurements
+ Rank : Relative position of current benchmark mean among all benchmarks (Arabic style)
+ Gen0 : GC Generation 0 collects per 1000 operations
+ Gen1 : GC Generation 1 collects per 1000 operations
+ Gen2 : GC Generation 2 collects per 1000 operations
+ Allocated : Allocated memory per single operation (managed only, inclusive, 1KB = 1024B)
+ 1 ns : 1 Nanosecond (0.000000001 sec)
+
+// * Diagnostic Output - MemoryDiagnoser *
+
+
+// ***** BenchmarkRunner: End *****
+Run time: 00:03:21 (201.53 sec), executed benchmarks: 10
+
+Global total time: 00:05:01 (301.12 sec), executed benchmarks: 10
+// * Artifacts cleanup *
+Artifacts cleanup is finished
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-default.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-default.md
new file mode 100644
index 0000000000..4dc2072d07
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-default.md
@@ -0,0 +1,13 @@
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ Job-RELKCN : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+IterationCount=3 IterationTime=100ms LaunchCount=1
+WarmupCount=3
+
+ Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio |
+--------- |---------:|---------:|---------:|------:|-------:|----------:|------------:|
+ Baseline | 19.08 μs | 3.570 μs | 0.196 μs | 1.00 | 3.5554 | 62.5 KB | 1.00 |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-github.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-github.md
new file mode 100644
index 0000000000..dc2900db3a
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report-github.md
@@ -0,0 +1,15 @@
+```
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ Job-RELKCN : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+IterationCount=3 IterationTime=100ms LaunchCount=1
+WarmupCount=3
+
+```
+| Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio |
+|--------- |---------:|---------:|---------:|------:|-------:|----------:|------------:|
+| Baseline | 19.08 μs | 3.570 μs | 0.196 μs | 1.00 | 3.5554 | 62.5 KB | 1.00 |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.csv b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.csv
new file mode 100644
index 0000000000..a399b5d71e
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.csv
@@ -0,0 +1,2 @@
+Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Ratio,Gen0,Allocated,Alloc Ratio
+Baseline,Job-RELKCN,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,100ms,1,Default,Default,Default,Default,Default,Default,16,3,19.08 μs,3.570 μs,0.196 μs,1.00,3.5554,62.5 KB,1.00
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.html b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.html
new file mode 100644
index 0000000000..af7ca40227
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-report.html
@@ -0,0 +1,32 @@
+
+
+
+
+Umbraco.Tests.Benchmarks.LoggerAllocationBenchmark-20251212-230708
+
+
+
+
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ Job-RELKCN : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+IterationCount=3 IterationTime=100ms LaunchCount=1
+WarmupCount=3
+
+
+
+| Method | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio |
+
+| Baseline | 19.08 μs | 3.570 μs | 0.196 μs | 1.00 | 3.5554 | 62.5 KB | 1.00 |
+
+
+
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md
new file mode 100644
index 0000000000..0a9c108140
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report-github.md
@@ -0,0 +1,25 @@
+```
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100-rc.2.25502.107
+ [Host] : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+
+Job=ShortRun IterationCount=3 LaunchCount=1
+WarmupCount=3
+
+```
+| Method | Mean | Error | StdDev | Median | Gen0 | Allocated |
+|------------------------------------------------------ |---------------:|--------------:|------------:|---------------:|-------:|----------:|
+| Linq | 51,195.5380 ns | 1,617.4345 ns | 88.6570 ns | 51,163.7063 ns | 3.4180 | 59712 B |
+| SplitToHeapStrings | 37,354.8894 ns | 9,999.4406 ns | 548.1031 ns | 37,333.8901 ns | 2.5635 | 44592 B |
+| SplitToStackSpansWithoutEmptyCheckReversingListAsSpan | 25,784.9531 ns | 1,949.3238 ns | 106.8490 ns | 25,818.4337 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithoutEmptyCheck | 26,441.8317 ns | 4,054.8077 ns | 222.2577 ns | 26,557.4375 ns | 0.9766 | 17128 B |
+| SplitToStackSpansWithEmptyCheck | 25,821.9195 ns | 4,840.3751 ns | 265.3173 ns | 25,718.1962 ns | 0.9766 | 17128 B |
+| StripWhitespace_Benchmark | 269.2084 ns | 46.5960 ns | 2.5541 ns | 267.8466 ns | 0.0033 | 64 B |
+| GetFileExtension_Benchmark | 308.9820 ns | 100.8086 ns | 5.5257 ns | 309.7014 ns | 0.0319 | 552 B |
+| StripHtml_Benchmark | 719.6788 ns | 182.4947 ns | 10.0031 ns | 718.6075 ns | 0.0019 | 48 B |
+| IsLowerCase_Benchmark | 0.0194 ns | 0.2102 ns | 0.0115 ns | 0.0218 ns | - | - |
+| IsUpperCase_Benchmark | 0.0078 ns | 0.2461 ns | 0.0135 ns | 0.0000 ns | - | - |
+| ReplaceNonAlphanumericChars_String_Benchmark | 84.6292 ns | 48.9647 ns | 2.6839 ns | 84.3141 ns | 0.0097 | 168 B |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv
new file mode 100644
index 0000000000..ad08a3b92d
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.csv
@@ -0,0 +1,12 @@
+Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Median,Gen0,Allocated
+Linq,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"51,195.5380 ns","1,617.4345 ns",88.6570 ns,"51,163.7063 ns",3.4180,59712 B
+SplitToHeapStrings,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"37,354.8894 ns","9,999.4406 ns",548.1031 ns,"37,333.8901 ns",2.5635,44592 B
+SplitToStackSpansWithoutEmptyCheckReversingListAsSpan,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"25,784.9531 ns","1,949.3238 ns",106.8490 ns,"25,818.4337 ns",0.9766,17128 B
+SplitToStackSpansWithoutEmptyCheck,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"26,441.8317 ns","4,054.8077 ns",222.2577 ns,"26,557.4375 ns",0.9766,17128 B
+SplitToStackSpansWithEmptyCheck,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,"25,821.9195 ns","4,840.3751 ns",265.3173 ns,"25,718.1962 ns",0.9766,17128 B
+StripWhitespace_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,269.2084 ns,46.5960 ns,2.5541 ns,267.8466 ns,0.0033,64 B
+GetFileExtension_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,308.9820 ns,100.8086 ns,5.5257 ns,309.7014 ns,0.0319,552 B
+StripHtml_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,719.6788 ns,182.4947 ns,10.0031 ns,718.6075 ns,0.0019,48 B
+IsLowerCase_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,0.0194 ns,0.2102 ns,0.0115 ns,0.0218 ns,0.0000,0 B
+IsUpperCase_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,0.0078 ns,0.2461 ns,0.0135 ns,0.0000 ns,0.0000,0 B
+ReplaceNonAlphanumericChars_String_Benchmark,ShortRun,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,3,Default,1,Default,Default,Default,Default,Default,Default,16,3,84.6292 ns,48.9647 ns,2.6839 ns,84.3141 ns,0.0097,168 B
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html
new file mode 100644
index 0000000000..abf5a64f7f
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-report.html
@@ -0,0 +1,42 @@
+
+
+
+
+Umbraco.Tests.Benchmarks.StringExtensionsBenchmarks-20251207-223758
+
+
+
+
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100-rc.2.25502.107
+ [Host] : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+ ShortRun : .NET 10.0.0 (10.0.0-rc.2.25502.107, 10.0.25.50307), X64 RyuJIT x86-64-v4
+
+Job=ShortRun IterationCount=3 LaunchCount=1
+WarmupCount=3
+
+
+
+| Method | Mean | Error | StdDev | Median | Gen0 | Allocated |
+
+| Linq | 51,195.5380 ns | 1,617.4345 ns | 88.6570 ns | 51,163.7063 ns | 3.4180 | 59712 B |
+
| SplitToHeapStrings | 37,354.8894 ns | 9,999.4406 ns | 548.1031 ns | 37,333.8901 ns | 2.5635 | 44592 B |
+
| SplitToStackSpansWithoutEmptyCheckReversingListAsSpan | 25,784.9531 ns | 1,949.3238 ns | 106.8490 ns | 25,818.4337 ns | 0.9766 | 17128 B |
+
| SplitToStackSpansWithoutEmptyCheck | 26,441.8317 ns | 4,054.8077 ns | 222.2577 ns | 26,557.4375 ns | 0.9766 | 17128 B |
+
| SplitToStackSpansWithEmptyCheck | 25,821.9195 ns | 4,840.3751 ns | 265.3173 ns | 25,718.1962 ns | 0.9766 | 17128 B |
+
| StripWhitespace_Benchmark | 269.2084 ns | 46.5960 ns | 2.5541 ns | 267.8466 ns | 0.0033 | 64 B |
+
| GetFileExtension_Benchmark | 308.9820 ns | 100.8086 ns | 5.5257 ns | 309.7014 ns | 0.0319 | 552 B |
+
| StripHtml_Benchmark | 719.6788 ns | 182.4947 ns | 10.0031 ns | 718.6075 ns | 0.0019 | 48 B |
+
| IsLowerCase_Benchmark | 0.0194 ns | 0.2102 ns | 0.0115 ns | 0.0218 ns | - | - |
+
| IsUpperCase_Benchmark | 0.0078 ns | 0.2461 ns | 0.0135 ns | 0.0000 ns | - | - |
+
| ReplaceNonAlphanumericChars_String_Benchmark | 84.6292 ns | 48.9647 ns | 2.6839 ns | 84.3141 ns | 0.0097 | 168 B |
+
+
+
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-default.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-default.md
new file mode 100644
index 0000000000..4af85a77de
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-default.md
@@ -0,0 +1,20 @@
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+ Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+----------------------- |----------------:|--------------:|--------------:|-----:|---------:|---------:|---------:|----------:|
+ Tiny_Ascii | 82.81 ns | 0.402 ns | 0.314 ns | 2 | 0.0027 | - | - | 48 B |
+ Tiny_Mixed | 71.05 ns | 0.225 ns | 0.176 ns | 1 | 0.0027 | - | - | 48 B |
+ Small_Ascii | 695.75 ns | 4.394 ns | 3.669 ns | 3 | 0.0124 | - | - | 224 B |
+ Small_Mixed | 686.54 ns | 8.868 ns | 8.295 ns | 3 | 0.0124 | - | - | 224 B |
+ Medium_Ascii | 5,994.68 ns | 32.905 ns | 30.779 ns | 4 | 0.4730 | - | - | 8240 B |
+ Medium_Mixed | 7,116.65 ns | 27.489 ns | 22.955 ns | 5 | 0.4730 | - | - | 8264 B |
+ Large_Ascii | 593,733.29 ns | 2,040.378 ns | 1,703.808 ns | 7 | 249.0234 | 249.0234 | 249.0234 | 819332 B |
+ Large_Mixed | 1,066,297.43 ns | 8,507.650 ns | 7,958.061 ns | 8 | 248.0469 | 248.0469 | 248.0469 | 823523 B |
+ Large_WorstCase | 2,148,169.56 ns | 16,455.374 ns | 15,392.367 ns | 9 | 246.0938 | 246.0938 | 246.0938 | 1024125 B |
+ CharArray_Medium_Mixed | 7,357.24 ns | 59.719 ns | 55.861 ns | 6 | 0.5951 | 0.0076 | - | 10336 B |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-github.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-github.md
new file mode 100644
index 0000000000..b6e0c570ac
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report-github.md
@@ -0,0 +1,22 @@
+```
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+```
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+|----------------------- |----------------:|--------------:|--------------:|-----:|---------:|---------:|---------:|----------:|
+| Tiny_Ascii | 82.81 ns | 0.402 ns | 0.314 ns | 2 | 0.0027 | - | - | 48 B |
+| Tiny_Mixed | 71.05 ns | 0.225 ns | 0.176 ns | 1 | 0.0027 | - | - | 48 B |
+| Small_Ascii | 695.75 ns | 4.394 ns | 3.669 ns | 3 | 0.0124 | - | - | 224 B |
+| Small_Mixed | 686.54 ns | 8.868 ns | 8.295 ns | 3 | 0.0124 | - | - | 224 B |
+| Medium_Ascii | 5,994.68 ns | 32.905 ns | 30.779 ns | 4 | 0.4730 | - | - | 8240 B |
+| Medium_Mixed | 7,116.65 ns | 27.489 ns | 22.955 ns | 5 | 0.4730 | - | - | 8264 B |
+| Large_Ascii | 593,733.29 ns | 2,040.378 ns | 1,703.808 ns | 7 | 249.0234 | 249.0234 | 249.0234 | 819332 B |
+| Large_Mixed | 1,066,297.43 ns | 8,507.650 ns | 7,958.061 ns | 8 | 248.0469 | 248.0469 | 248.0469 | 823523 B |
+| Large_WorstCase | 2,148,169.56 ns | 16,455.374 ns | 15,392.367 ns | 9 | 246.0938 | 246.0938 | 246.0938 | 1024125 B |
+| CharArray_Medium_Mixed | 7,357.24 ns | 59.719 ns | 55.861 ns | 6 | 0.5951 | 0.0076 | - | 10336 B |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.csv b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.csv
new file mode 100644
index 0000000000..f1afabcceb
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.csv
@@ -0,0 +1,11 @@
+Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Rank,Gen0,Gen1,Gen2,Allocated
+Tiny_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,82.81 ns,0.402 ns,0.314 ns,2,0.0027,0.0000,0.0000,48 B
+Tiny_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,71.05 ns,0.225 ns,0.176 ns,1,0.0027,0.0000,0.0000,48 B
+Small_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,695.75 ns,4.394 ns,3.669 ns,3,0.0124,0.0000,0.0000,224 B
+Small_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,686.54 ns,8.868 ns,8.295 ns,3,0.0124,0.0000,0.0000,224 B
+Medium_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"5,994.68 ns",32.905 ns,30.779 ns,4,0.4730,0.0000,0.0000,8240 B
+Medium_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"7,116.65 ns",27.489 ns,22.955 ns,5,0.4730,0.0000,0.0000,8264 B
+Large_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"593,733.29 ns","2,040.378 ns","1,703.808 ns",7,249.0234,249.0234,249.0234,819332 B
+Large_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"1,066,297.43 ns","8,507.650 ns","7,958.061 ns",8,248.0469,248.0469,248.0469,823523 B
+Large_WorstCase,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"2,148,169.56 ns","16,455.374 ns","15,392.367 ns",9,246.0938,246.0938,246.0938,1024125 B
+CharArray_Medium_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"7,357.24 ns",59.719 ns,55.861 ns,6,0.5951,0.0076,0.0000,10336 B
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.html b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.html
new file mode 100644
index 0000000000..96fde76fff
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-report.html
@@ -0,0 +1,39 @@
+
+
+
+
+Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBaselineBenchmarks-20251212-230710
+
+
+
+
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+
+
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+
+| Tiny_Ascii | 82.81 ns | 0.402 ns | 0.314 ns | 2 | 0.0027 | - | - | 48 B |
+
| Tiny_Mixed | 71.05 ns | 0.225 ns | 0.176 ns | 1 | 0.0027 | - | - | 48 B |
+
| Small_Ascii | 695.75 ns | 4.394 ns | 3.669 ns | 3 | 0.0124 | - | - | 224 B |
+
| Small_Mixed | 686.54 ns | 8.868 ns | 8.295 ns | 3 | 0.0124 | - | - | 224 B |
+
| Medium_Ascii | 5,994.68 ns | 32.905 ns | 30.779 ns | 4 | 0.4730 | - | - | 8240 B |
+
| Medium_Mixed | 7,116.65 ns | 27.489 ns | 22.955 ns | 5 | 0.4730 | - | - | 8264 B |
+
| Large_Ascii | 593,733.29 ns | 2,040.378 ns | 1,703.808 ns | 7 | 249.0234 | 249.0234 | 249.0234 | 819332 B |
+
| Large_Mixed | 1,066,297.43 ns | 8,507.650 ns | 7,958.061 ns | 8 | 248.0469 | 248.0469 | 248.0469 | 823523 B |
+
| Large_WorstCase | 2,148,169.56 ns | 16,455.374 ns | 15,392.367 ns | 9 | 246.0938 | 246.0938 | 246.0938 | 1024125 B |
+
| CharArray_Medium_Mixed | 7,357.24 ns | 59.719 ns | 55.861 ns | 6 | 0.5951 | 0.0076 | - | 10336 B |
+
+
+
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-default.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-default.md
new file mode 100644
index 0000000000..808afff330
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-default.md
@@ -0,0 +1,20 @@
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+ Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+------------------ |-----------------:|---------------:|---------------:|-----:|---------:|---------:|---------:|----------:|
+ Tiny_Ascii | 6.756 ns | 0.1042 ns | 0.0974 ns | 1 | - | - | - | - |
+ Tiny_Mixed | 6.554 ns | 0.0153 ns | 0.0143 ns | 1 | - | - | - | - |
+ Small_Ascii | 8.132 ns | 0.0271 ns | 0.0253 ns | 2 | - | - | - | - |
+ Small_Mixed | 308.895 ns | 0.6975 ns | 0.6525 ns | 4 | 0.0129 | - | - | 224 B |
+ Medium_Ascii | 38.200 ns | 0.2104 ns | 0.1968 ns | 3 | - | - | - | - |
+ Medium_Mixed | 4,213.825 ns | 43.6474 ns | 40.8278 ns | 6 | 0.1221 | - | - | 2216 B |
+ Large_Ascii | 4,327.400 ns | 23.7729 ns | 21.0740 ns | 6 | - | - | - | - |
+ Large_Mixed | 791,424.668 ns | 4,670.0767 ns | 4,368.3927 ns | 7 | 57.6172 | 57.6172 | 57.6172 | 220856 B |
+ Large_WorstCase | 2,275,919.826 ns | 27,753.5138 ns | 25,960.6540 ns | 8 | 105.4688 | 105.4688 | 105.4688 | 409763 B |
+ Span_Medium_Mixed | 3,743.828 ns | 8.5415 ns | 7.5718 ns | 5 | 0.0038 | - | - | 120 B |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-github.md b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-github.md
new file mode 100644
index 0000000000..a6f769fb99
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report-github.md
@@ -0,0 +1,22 @@
+```
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+```
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+|------------------ |-----------------:|---------------:|---------------:|-----:|---------:|---------:|---------:|----------:|
+| Tiny_Ascii | 6.756 ns | 0.1042 ns | 0.0974 ns | 1 | - | - | - | - |
+| Tiny_Mixed | 6.554 ns | 0.0153 ns | 0.0143 ns | 1 | - | - | - | - |
+| Small_Ascii | 8.132 ns | 0.0271 ns | 0.0253 ns | 2 | - | - | - | - |
+| Small_Mixed | 308.895 ns | 0.6975 ns | 0.6525 ns | 4 | 0.0129 | - | - | 224 B |
+| Medium_Ascii | 38.200 ns | 0.2104 ns | 0.1968 ns | 3 | - | - | - | - |
+| Medium_Mixed | 4,213.825 ns | 43.6474 ns | 40.8278 ns | 6 | 0.1221 | - | - | 2216 B |
+| Large_Ascii | 4,327.400 ns | 23.7729 ns | 21.0740 ns | 6 | - | - | - | - |
+| Large_Mixed | 791,424.668 ns | 4,670.0767 ns | 4,368.3927 ns | 7 | 57.6172 | 57.6172 | 57.6172 | 220856 B |
+| Large_WorstCase | 2,275,919.826 ns | 27,753.5138 ns | 25,960.6540 ns | 8 | 105.4688 | 105.4688 | 105.4688 | 409763 B |
+| Span_Medium_Mixed | 3,743.828 ns | 8.5415 ns | 7.5718 ns | 5 | 0.0038 | - | - | 120 B |
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.csv b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.csv
new file mode 100644
index 0000000000..c8e66bc28e
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.csv
@@ -0,0 +1,11 @@
+Method,Job,AnalyzeLaunchVariance,EvaluateOverhead,MaxAbsoluteError,MaxRelativeError,MinInvokeCount,MinIterationTime,OutlierMode,Affinity,EnvironmentVariables,Jit,LargeAddressAware,Platform,PowerPlanMode,Runtime,AllowVeryLargeObjects,Concurrent,CpuGroups,Force,HeapAffinitizeMask,HeapCount,NoAffinitize,RetainVm,Server,Arguments,BuildConfiguration,Clock,EngineFactory,NuGetReferences,Toolchain,IsMutator,InvocationCount,IterationCount,IterationTime,LaunchCount,MaxIterationCount,MaxWarmupIterationCount,MemoryRandomization,MinIterationCount,MinWarmupIterationCount,RunStrategy,UnrollFactor,WarmupCount,Mean,Error,StdDev,Rank,Gen0,Gen1,Gen2,Allocated
+Tiny_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,6.756 ns,0.1042 ns,0.0974 ns,1,0.0000,0.0000,0.0000,0 B
+Tiny_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,6.554 ns,0.0153 ns,0.0143 ns,1,0.0000,0.0000,0.0000,0 B
+Small_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,8.132 ns,0.0271 ns,0.0253 ns,2,0.0000,0.0000,0.0000,0 B
+Small_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,308.895 ns,0.6975 ns,0.6525 ns,4,0.0129,0.0000,0.0000,224 B
+Medium_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,38.200 ns,0.2104 ns,0.1968 ns,3,0.0000,0.0000,0.0000,0 B
+Medium_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"4,213.825 ns",43.6474 ns,40.8278 ns,6,0.1221,0.0000,0.0000,2216 B
+Large_Ascii,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"4,327.400 ns",23.7729 ns,21.0740 ns,6,0.0000,0.0000,0.0000,0 B
+Large_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"791,424.668 ns","4,670.0767 ns","4,368.3927 ns",7,57.6172,57.6172,57.6172,220856 B
+Large_WorstCase,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"2,275,919.826 ns","27,753.5138 ns","25,960.6540 ns",8,105.4688,105.4688,105.4688,409763 B
+Span_Medium_Mixed,DefaultJob,False,Default,Default,Default,Default,Default,Default,1111111111111111,Empty,RyuJit,Default,X64,8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c,.NET 10.0,False,True,False,True,Default,Default,False,False,False,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,Default,16,Default,"3,743.828 ns",8.5415 ns,7.5718 ns,5,0.0038,0.0000,0.0000,120 B
diff --git a/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.html b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.html
new file mode 100644
index 0000000000..2a39067e6a
--- /dev/null
+++ b/BenchmarkDotNet.Artifacts/results/Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-report.html
@@ -0,0 +1,39 @@
+
+
+
+
+Umbraco.Tests.Benchmarks.Utf8ToAsciiConverterBenchmarks-20251213-034127
+
+
+
+
+
+BenchmarkDotNet v0.15.6, Linux Ubuntu 25.10 (Questing Quokka)
+Intel Xeon CPU 2.80GHz, 1 CPU, 16 logical and 8 physical cores
+.NET SDK 10.0.100
+ [Host] : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+ DefaultJob : .NET 10.0.0 (10.0.0, 10.0.25.52411), X64 RyuJIT x86-64-v4
+
+
+
+
+| Method | Mean | Error | StdDev | Rank | Gen0 | Gen1 | Gen2 | Allocated |
+
+| Tiny_Ascii | 6.756 ns | 0.1042 ns | 0.0974 ns | 1 | - | - | - | - |
+
| Tiny_Mixed | 6.554 ns | 0.0153 ns | 0.0143 ns | 1 | - | - | - | - |
+
| Small_Ascii | 8.132 ns | 0.0271 ns | 0.0253 ns | 2 | - | - | - | - |
+
| Small_Mixed | 308.895 ns | 0.6975 ns | 0.6525 ns | 4 | 0.0129 | - | - | 224 B |
+
| Medium_Ascii | 38.200 ns | 0.2104 ns | 0.1968 ns | 3 | - | - | - | - |
+
| Medium_Mixed | 4,213.825 ns | 43.6474 ns | 40.8278 ns | 6 | 0.1221 | - | - | 2216 B |
+
| Large_Ascii | 4,327.400 ns | 23.7729 ns | 21.0740 ns | 6 | - | - | - | - |
+
| Large_Mixed | 791,424.668 ns | 4,670.0767 ns | 4,368.3927 ns | 7 | 57.6172 | 57.6172 | 57.6172 | 220856 B |
+
| Large_WorstCase | 2,275,919.826 ns | 27,753.5138 ns | 25,960.6540 ns | 8 | 105.4688 | 105.4688 | 105.4688 | 409763 B |
+
| Span_Medium_Mixed | 3,743.828 ns | 8.5415 ns | 7.5718 ns | 5 | 0.0038 | - | - | 120 B |
+
+
+
diff --git a/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-1.md b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-1.md
new file mode 100644
index 0000000000..80c294ec17
--- /dev/null
+++ b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-1.md
@@ -0,0 +1,192 @@
+# Critical Architectural Review: ContentService Refactoring Design
+
+**Reviewed Document:** `docs/plans/2025-12-19-contentservice-refactor-design.md`
+**Review Date:** 2025-12-19
+**Reviewer Role:** Senior Principal Software Architect
+
+---
+
+## 1. Overall Assessment
+
+**Strengths:**
+- Correctly identifies a real maintainability problem (~3800 lines monolith)
+- Preserves backward compatibility via facade pattern (essential for Umbraco ecosystem)
+- Clear separation by functional domain (CRUD, Publishing, Move)
+- Aligns with Umbraco's existing layered architecture (interfaces in Core, implementations in Infrastructure)
+
+**Major Concerns:**
+- **Naming collision** with existing `ContentPublishingService` already in codebase
+- **Cross-service transaction coordination** inadequately addressed
+- **Arbitrary public/internal distinction** doesn't match actual usage patterns
+- **Missing mapping** for several existing methods that don't fit cleanly into proposed services
+
+---
+
+## 2. Critical Issues
+
+### 2.1 Naming Collision with Existing ContentPublishingService
+
+**Description:** A `ContentPublishingService` already exists at `src/Umbraco.Core/Services/ContentPublishingService.cs:16` with interface `IContentPublishingService`. The proposed `IContentPublishingService` would directly conflict.
+
+**Impact:** Build failure or confusing namespace disambiguation; existing consumers of `IContentPublishingService` would break or become ambiguous.
+
+**Suggestion:** Rename the proposed interface to `IContentPublishOperationService` or `IContentPublicationService`, OR refactor the existing `ContentPublishingService` to use the new infrastructure.
+
+---
+
+### 2.2 Cross-Service Dependencies Create Circular Risk
+
+**Description:** The proposed services have intrinsic coupling:
+- `MoveToRecycleBin` (Move) fires `ContentUnpublishedNotification` for published content (requires Publishing awareness)
+- `Publish` (Publishing) calls `Save` internally (requires CRUD)
+- `Copy` (Move) calls `Save` and checks `GetPermissions` (requires CRUD and Permissions)
+
+**Impact:** Either circular dependencies between services OR the facade must orchestrate complex multi-service operations, defeating decomposition benefits.
+
+**Suggestion:** Extract a shared `ContentOperationOrchestrator` that coordinates cross-cutting operations, or make Publishing/Move depend on CRUD (unidirectional), with explicit dependency documentation.
+
+---
+
+### 2.3 Transaction Boundary Ownership Unclear
+
+**Description:** The design states "Ensure scopes work across service calls" but doesn't specify:
+- Who creates the scope when `ContentMoveService.MoveToRecycleBin` needs to unpublish content?
+- Can services assume they're called within an existing scope, or must each method create its own?
+- How do nested scope behaviors work when Service A calls Service B?
+
+**Impact:** Inconsistent transaction handling could lead to partial commits, audit log inconsistencies, or notification ordering issues.
+
+**Suggestion:** Define explicit scope ownership rules:
+- **Option A:** All public service methods create their own scope (simple, but nested operations may have issues)
+- **Option B:** Services accept optional `ICoreScope` parameter for caller-managed transactions
+- **Option C:** Use ambient scope pattern consistently (document the pattern)
+
+---
+
+### 2.4 Arbitrary Public vs Internal Classification
+
+**Description:** The design classifies:
+- **Public:** CRUD, Publishing, Move
+- **Internal:** Versioning, Query, Permission, Blueprint
+
+But examining actual usage:
+- `GetVersions`, `Rollback`, `DeleteVersions` are public on `IContentService`
+- `GetPermissions`, `SetPermissions` are public on `IContentService`
+- `GetPagedChildren`, `GetAncestors`, `Count` are frequently used externally
+- Blueprints have public API methods
+
+**Impact:** Internal helpers cannot be injected by consumers who need specific functionality. Forces continued use of `IContentService` facade for everything.
+
+**Suggestion:** Either:
+- Make Query and Versioning public (they represent distinct concerns API consumers need)
+- OR keep all as internal and document that `IContentService` remains the public API (current approach but explicitly stated)
+
+---
+
+### 2.5 Missing Method Mappings
+
+**Description:** Several existing methods don't cleanly map to proposed services:
+
+| Method | Proposed Location | Problem |
+|--------|------------------|---------|
+| `SendToPublication` | ? | Not listed, involves Save + events |
+| `CheckDataIntegrity` | ? | Not listed, infrastructure concern |
+| `DeleteOfTypes` | CRUD? Move? | Moves children to bin, then deletes |
+| `CommitDocumentChanges` | Publishing? | Internal but critical for scheduling |
+| `GetPublishedChildren` | Query? Publishing? | Uses Published status (domain crossover) |
+
+**Impact:** Implementation will encounter methods that don't fit, leading to ad-hoc placement or leaky abstractions.
+
+**Suggestion:** Create explicit method-to-service mapping table covering ALL 80+ methods in current `IContentService`. Identify "orchestration" methods that may stay in facade.
+
+---
+
+### 2.6 Notification Consistency Risk
+
+**Description:** ContentService fires ~20 different notification types (`ContentSaving`, `ContentPublishing`, `ContentMoving`, etc.) with specific state propagation via `WithStateFrom()`. Splitting services means:
+- Each service must correctly fire its subset of notifications
+- State must be preserved across service boundaries
+- Notification ordering must remain consistent
+
+**Impact:** Breaking notification contracts would affect cache invalidation, webhooks, search indexing, and third-party packages.
+
+**Suggestion:** Add explicit notification responsibility matrix to design. Consider a `ContentNotificationService` that centralizes notification logic, called by all sub-services.
+
+---
+
+## 3. Alternative Architectural Challenge
+
+### Alternative: Vertical Slicing by Operation Complexity
+
+Instead of horizontal domain slicing (CRUD/Publishing/Move), slice vertically by operation complexity:
+
+**Proposed Structure:**
+1. `ContentReadService` - All read operations (Get, Count, Query, Versions read-only)
+2. `ContentWriteService` - All simple mutations (Create, Save, Delete)
+3. `ContentWorkflowService` - All complex stateful operations (Publish, Unpublish, Schedule, Move, MoveToRecycleBin)
+
+**Pro:** Matches actual dependency patterns - reads are independent, writes have minimal coupling, workflows can depend on both. Simpler transaction model.
+
+**Con:** Workflows service could still grow large; doesn't solve the "where does Copy go" problem.
+
+---
+
+## 4. Minor Issues & Improvements
+
+### 4.1 Line Count Estimates May Be Optimistic
+
+The `ContentPublishingService` is estimated at ~800 lines, but `CommitDocumentChangesInternal` alone is 330+ lines with complex culture/scheduling logic. Consider splitting publishing into Immediate vs Scheduled sub-components.
+
+### 4.2 Missing Async Consideration
+
+Existing `EmptyRecycleBinAsync` suggests async patterns are emerging. New services should define async-first interfaces where database operations are involved.
+
+### 4.3 No Explicit Interface for ContentServiceBase
+
+The design shows `ContentServiceBase` as abstract class but doesn't specify if it implements any interface. Consider `IContentServiceBase` for testing.
+
+### 4.4 Helper Naming Convention
+
+"Helper" suffix is discouraged in modern .NET. Consider `ContentVersionManager`, `ContentQueryExecutor`, etc.
+
+---
+
+## 5. Questions for Clarification
+
+1. **Existing IContentPublishingService:** Should the current `ContentPublishingService` be refactored to use the new infrastructure, replaced, or renamed?
+
+2. **Branch Publishing:** The complex `PublishBranch` operation (200+ lines) spans publishing AND tree traversal. Which service owns it?
+
+3. **Locking Strategy:** Current code uses explicit `scope.WriteLock(Constants.Locks.ContentTree)`. Will each sub-service acquire locks independently, or is there a coordination pattern?
+
+4. **Culture-Variant Complexity:** The `CommitDocumentChangesInternal` method handles 15+ different publish result types with culture awareness. Is this complexity remaining in one place or distributed?
+
+5. **RepositoryService Base Class:** Current `ContentService : RepositoryService`. Do new services also inherit this, or get dependencies differently?
+
+---
+
+## 6. Final Recommendation
+
+### Major Revisions Needed
+
+The design addresses a real problem and the overall direction is sound, but implementation will hit significant obstacles without addressing the following:
+
+| Priority | Action Item | Status |
+|----------|-------------|--------|
+| **P0** | Resolve naming collision with existing `ContentPublishingService` | Required |
+| **P0** | Document transaction/scope ownership explicitly | Required |
+| **P0** | Create complete method mapping covering all 80+ IContentService methods | Required |
+| **P1** | Define notification responsibility matrix per service | Required |
+| **P1** | Reconsider public/internal classification based on actual API usage patterns | Recommended |
+| **P1** | Address cross-service dependency direction (who can call whom) | Recommended |
+
+Once these are addressed, the refactoring approach is viable and would meaningfully improve maintainability.
+
+---
+
+## Appendix: Key Files Reviewed
+
+- `src/Umbraco.Core/Services/ContentService.cs` (3824 lines)
+- `src/Umbraco.Core/Services/IContentService.cs` (522 lines, ~80 methods)
+- `src/Umbraco.Core/Services/ContentPublishingService.cs` (existing, conflicts with proposal)
+- `src/Umbraco.Core/CLAUDE.md` (architecture patterns reference)
diff --git a/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-2.md b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-2.md
new file mode 100644
index 0000000000..33f4f73ad1
--- /dev/null
+++ b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-2.md
@@ -0,0 +1,469 @@
+# Critical Architectural Review: ContentService Refactoring Design v1.5
+
+**Reviewed Document:** `docs/plans/2025-12-19-contentservice-refactor-design.md`
+**Review Date:** 2025-12-20
+**Reviewer Role:** Senior Principal Software Architect
+**Document Revision:** 1.5 (includes performance benchmarks)
+**Review Revision:** 2.0 (incorporates clarifications and deep-dive analysis)
+
+---
+
+## Executive Summary
+
+The ContentService refactoring design is **approved with changes**. The core architecture is sound, the phased approach provides good risk mitigation, and the design addresses a real maintainability problem. This review incorporates deep-dive analysis of locking infrastructure, performance testing strategy, and clarifications on key architectural decisions.
+
+### Key Clarifications Incorporated
+
+| Question | Decision |
+|----------|----------|
+| IContentService facade lifespan | **Remains indefinitely** - not deprecated |
+| Persistence layer | **NPoco repositories first** - EF Core migration is separate concern |
+| Hierarchical locking | **Phase 9** - post-refactoring optimization |
+| Performance testing | **Extend existing pattern** - use integration test infrastructure |
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- **Comprehensive method mapping** - All 80+ `IContentService` methods explicitly mapped to target services
+- **Clear dependency direction** - Unidirectional: PublishOperation/Move → CRUD only; no circular dependencies
+- **Solid transaction model** - Ambient scope pattern well-documented with facade orchestration
+- **Extensive notification matrix** - Each notification assigned to specific service with state preservation
+- **Test-first approach** - 15 targeted integration tests + benchmarks with phase gates
+- **Performance awareness** - N+1 queries and memory allocation issues identified with specific line numbers
+
+### Concerns Addressed in This Review
+
+| Concern | Resolution |
+|---------|------------|
+| Lock contention bottleneck | Defer to Phase 9; document lock contracts during extraction |
+| Benchmark infrastructure gaps | Extend existing `ContentServicePerformanceTest` pattern |
+| Performance optimization timing | Separate from extraction phases |
+| Baseline comparison workflow | Structured JSON output with manual comparison |
+
+---
+
+## 2. Critical Issues
+
+### 2.1 Lock Contention Architecture (Documented Limitation)
+
+**Current State Analysis:**
+
+The ContentService contains 58 lock acquisition points:
+- 31 `ReadLock(Constants.Locks.ContentTree)`
+- 27 `WriteLock(Constants.Locks.ContentTree)`
+- All use the SAME global lock
+
+**Primary Bottleneck - `PerformMoveLocked` (lines 2570-2620):**
+
+```csharp
+// Holds WriteLock while iterating ALL descendants
+const int pageSize = 500;
+do {
+ foreach (IContent descendant in descendants) {
+ PerformMoveContentLocked(descendant, userId, trash); // DB write per item
+ }
+} while (total > pageSize);
+```
+
+Moving a tree with 5,000 descendants holds the global lock for the duration of 5,000+ database writes.
+
+**Decision:** Accept as known limitation during extraction phases. Implement hierarchical locking in Phase 9.
+
+**Mitigation:** Each new service must document its lock contract (see Section 5.2).
+
+---
+
+### 2.2 Performance Optimization Phasing
+
+**Issue:** The design mixes 20+ performance optimizations with refactoring phases without clear separation.
+
+**Resolution:** Performance optimizations are separated into distinct phases:
+
+| Phase | Focus | Performance Work |
+|-------|-------|------------------|
+| 0-8 | Extraction | **None** - preserve existing behavior |
+| 9 | Locking | Hierarchical/fine-grained locking |
+| 10+ | Optimization | N+1 fixes, memory allocation, caching |
+
+**Rationale:**
+1. Mixing refactoring with optimization compounds risk
+2. Benchmarks can measure each improvement independently
+3. Extraction phases remain focused on code organization
+
+---
+
+### 2.3 Benchmark Infrastructure
+
+**Issue:** The design proposed custom benchmark infrastructure (33 tests, JSON output, regression detection) that duplicates effort.
+
+**Resolution:** Extend existing `ContentServicePerformanceTest` pattern.
+
+**Existing Infrastructure:**
+- `ContentServicePerformanceTest.cs` - Established pattern with `Stopwatch`
+- `[LongRunning]` attribute - Category filter for slow tests
+- `TestProfiler` - MiniProfiler integration for SQL tracing
+- `UmbracoIntegrationTestWithContent` - Base class with pre-created content
+- Full DI + SQLite database - Integration test infrastructure
+
+**New Infrastructure Created:**
+- `ContentServiceBenchmarkBase.cs` - Extends existing pattern with structured output
+- JSON markers for automated extraction: `[BENCHMARK_JSON]...[/BENCHMARK_JSON]`
+- `MeasureAndRecord()` helper methods
+
+**Benchmark Execution:**
+```bash
+# Capture baseline (before Phase 0)
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "Category=Benchmark" \
+ --logger "console;verbosity=detailed" | tee benchmark-baseline.txt
+
+# Extract JSON results
+grep -oP '\[BENCHMARK_JSON\]\K.*(?=\[/BENCHMARK_JSON\])' benchmark-baseline.txt > baseline.json
+```
+
+---
+
+### 2.4 DeleteOfType/DeleteOfTypes Placement
+
+**Issue:** These methods are mapped to `IContentCrudService` but require orchestration (move descendants to bin first).
+
+**Resolution:** Move to Facade.
+
+**Updated Facade Orchestration Methods:**
+
+| Method | Why in Facade |
+|--------|---------------|
+| `MoveToRecycleBin` | Unpublishes content then moves |
+| `DeleteOfType` | Moves descendants to bin, then deletes type content |
+| `DeleteOfTypes` | Moves descendants to bin, then deletes multiple type content |
+
+---
+
+## 3. Architectural Decisions
+
+### 3.1 IContentService Facade Permanence
+
+**Decision:** The `IContentService` facade remains indefinitely as the stable public API.
+
+**Implications:**
+- External consumers (packages, integrations) continue using `IContentService`
+- New granular services (`IContentCrudService`, etc.) are available for internal use and advanced scenarios
+- No deprecation warnings on `IContentService`
+- Facade overhead is acceptable for API stability
+
+**Documentation Requirement:** Add to design document:
+> The `IContentService` interface and its facade implementation are permanent public API.
+> The granular services provide decomposition benefits internally while maintaining
+> backward compatibility for all existing consumers.
+
+---
+
+### 3.2 NPoco Repository Implementation
+
+**Decision:** Implement all new services against NPoco repositories first.
+
+**Implications:**
+- Use existing `IDocumentRepository` (NPoco-based)
+- No EF Core dependencies in initial implementation
+- EF Core migration is a separate initiative
+- Services are persistence-agnostic via repository interfaces
+
+**Implementation Pattern:**
+```csharp
+public class ContentCrudService : ContentServiceBase, IContentCrudService
+{
+ private readonly IDocumentRepository _documentRepository; // NPoco
+
+ // Implementation uses existing repository patterns
+}
+```
+
+---
+
+### 3.3 Hierarchical Locking (Phase 9)
+
+**Decision:** Defer hierarchical/fine-grained locking to Phase 9, after extraction is complete.
+
+**Rationale:**
+1. **Clearer ownership** - After extraction, each service owns its locks
+2. **Easier to reason about** - 10-15 lock points per service vs. 58 in monolith
+3. **Measurable** - Benchmarks show actual impact
+4. **Risk isolation** - Locking changes isolated from refactoring
+
+**Phase 9 Scope:**
+- Design lock hierarchy (path-based or operation-based)
+- Update scope infrastructure if needed
+- Migrate each service to granular locks
+- Benchmark comparison
+
+**Estimated Effort:** 3-5 days
+
+**Possible Approaches:**
+```csharp
+// Option A: Path-based locks (lock subtree only)
+scope.WriteLock(Constants.Locks.ContentTree, content.Path);
+
+// Option B: Operation-specific locks
+scope.WriteLock(Constants.Locks.ContentTreeMove);
+scope.WriteLock(Constants.Locks.ContentTreePublish);
+
+// Option C: Hybrid (operation + path)
+scope.WriteLock(Constants.Locks.ContentTreeMove, content.Path);
+```
+
+---
+
+## 4. Performance Testing Strategy
+
+### 4.1 Benchmark Timing
+
+| Checkpoint | When | Purpose |
+|------------|------|---------|
+| **Baseline** | Before Phase 0 | Capture current behavior before ANY changes |
+| **Phase 1** | After CRUD Service | Validate foundation patterns |
+| **Phase 5** | After Publish Operation | Highest-risk phase (N+1 hotspots) |
+| **Phase 8** | After Facade | Final validation - all services integrated |
+| **Phase 9** | After Locking | Measure lock optimization impact |
+
+**Exception Rule:** If a phase encounters unexpected complexity or touches a known hotspot, run benchmarks immediately after.
+
+### 4.2 Prioritized Benchmarks
+
+Based on identified hotspots in the design document:
+
+| Priority | Benchmark | Target | Hotspot |
+|----------|-----------|--------|---------|
+| **P0** | `GetContentSchedulesByIds_100Items` | N+1 at line 1025-1049 | `_idKeyMap.GetIdForKey` loop |
+| **P0** | `PublishBranch_100Items` | Lock contention | Tree traversal under lock |
+| **P0** | `MoveToRecycleBin_LargeTree` | Lock duration | `PerformMoveLocked` line 2600+ |
+| **P1** | `Save_BatchOf100` | Core CRUD | Baseline mutation performance |
+| **P1** | `GetAncestors_10Levels` | N+1 prone | Repeated single lookups line 792 |
+| **P1** | `EmptyRecycleBin_100Items` | Lock duration | Delete loop under lock |
+| **P2** | `Sort_100Children` | Notification ordering | Cross-service coordination |
+| **P2** | `Copy_Recursive_50Items` | Cross-service | Recursive operation |
+
+### 4.3 Baseline Comparison Workflow
+
+**Capture:**
+```bash
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "Category=Benchmark&FullyQualifiedName~ContentServiceRefactoringBenchmarks" \
+ --logger "console;verbosity=detailed" 2>&1 | tee benchmark-$(git rev-parse --short HEAD).txt
+```
+
+**Compare:**
+```bash
+# Manual comparison of JSON outputs
+diff baseline.json current.json
+
+# Or simple script
+jq -s '.[0] as $base | .[1] | to_entries | map({
+ name: .key,
+ baseline: $base[.key].ElapsedMs,
+ current: .value.ElapsedMs,
+ change: ((.value.ElapsedMs - $base[.key].ElapsedMs) / $base[.key].ElapsedMs * 100 | round)
+})' baseline.json current.json
+```
+
+**Regression Threshold:** 20% degradation triggers investigation (manual, not automated).
+
+---
+
+## 5. Implementation Requirements
+
+### 5.1 Updated Phase Structure
+
+| Phase | Service | Lock Documentation | Benchmarks |
+|-------|---------|-------------------|------------|
+| 0 | Write tests | N/A | **Run baseline** |
+| 1 | CRUD Service | Document lock contract | **Run benchmarks** |
+| 2 | Query Service | Document lock contract | - |
+| 3 | Version Service | Document lock contract | - |
+| 4 | Move Service | Document lock contract | - |
+| 5 | Publish Operation | Document lock contract | **Run benchmarks** |
+| 6 | Permission Manager | Document lock contract | - |
+| 7 | Blueprint Manager | Document lock contract | - |
+| 8 | Facade | Verify all contracts | **Run benchmarks** |
+| 9 | Locking Optimization | Implement changes | **Run benchmarks** |
+| 10+ | Performance Optimization | N/A | Per-optimization |
+
+### 5.2 Lock Contract Documentation Template
+
+Each new service interface must include:
+
+```csharp
+///
+/// Provides move, copy, and recycle bin operations for content.
+///
+///
+/// Lock Contract:
+///
+/// - WriteLock(ContentTree): Move, MoveToRecycleBin, Copy, Sort, EmptyRecycleBin
+/// - ReadLock(ContentTree): GetPagedContentInRecycleBin, RecycleBinSmells
+///
+///
+/// Lock Duration Concerns:
+///
+/// - Move/MoveToRecycleBin: Iterates descendants, O(n) lock duration
+/// - EmptyRecycleBin: Deletes all bin content, O(n) lock duration
+///
+///
+/// Phase 9 Optimization Opportunity:
+///
+/// - Move/Copy: Could use subtree locks (lock path prefix)
+/// - Sort: Only needs lock on parent node
+///
+///
+public interface IContentMoveService
+{
+ // ...
+}
+```
+
+### 5.3 Git Checkpoint Strategy
+
+Add to regression protocol:
+
+```
+1. Create tagged commit at each phase gate completion
+ git tag phase-1-complete -m "CRUD Service extraction complete"
+
+2. If phase fails testing, revert to previous tag
+ git reset --hard phase-0-complete
+
+3. Benchmark results stored with commit hash
+ benchmark-{commit-hash}.json
+```
+
+---
+
+## 6. Minor Issues & Improvements
+
+### 6.1 Phase Gate Test Commands
+
+**Issue:** Current filter matches too broadly.
+
+**Fix:**
+```bash
+# Refactoring-specific tests (fast feedback)
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "FullyQualifiedName~ContentServiceRefactoringTests"
+
+# All ContentService tests (phase gate) - more specific
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "FullyQualifiedName~Umbraco.Infrastructure.Services.ContentService"
+```
+
+### 6.2 API Layer Impact
+
+**Clarification needed:** The Management API (`Umbraco.Cms.Api.Management`) exposes content operations.
+
+**Resolution:** No API changes required.
+
+> The existing `IContentPublishingService` (API layer) continues to use `IContentService` facade.
+> After refactoring, it indirectly uses new services through the unchanged facade interface.
+> No API version bump or endpoint changes needed.
+
+### 6.3 Existing Benchmarks Project
+
+**Analysis:** The `Umbraco.Tests.Benchmarks` project with BenchmarkDotNet does NOT meet the needs:
+
+| Requirement | Status |
+|-------------|--------|
+| BenchmarkDotNet | Available (v0.15.6) |
+| Database access | Missing |
+| Service DI container | Missing |
+| Integration test base class | Missing |
+
+**Decision:** Use integration test infrastructure instead. The existing `ContentServicePerformanceTest` pattern is battle-tested and provides full database/DI access.
+
+---
+
+## 7. Questions Resolved
+
+| # | Question | Resolution |
+|---|----------|------------|
+| 1 | Baseline timing | Before Phase 0, before any code changes |
+| 2 | BenchmarkDotNet vs custom | Extend existing integration test pattern |
+| 3 | Lock contention acceptance | Accept during extraction; optimize in Phase 9 |
+| 4 | Facade deprecation path | No deprecation - remains indefinitely |
+| 5 | EF Core vs NPoco | NPoco first; EF Core migration is separate |
+
+---
+
+## 8. First Component to Fail Analysis
+
+Under increasing concurrent load, the following failure sequence is predicted:
+
+| Order | Component | Failure Mode | Mitigation |
+|-------|-----------|--------------|------------|
+| 1st | `GetContentSchedulesByIds` | N+1 queries exhaust connection pool (~50 concurrent) | Phase 10: Batch lookup |
+| 2nd | `PublishBranch` | Lock held during tree traversal blocks all writes | Phase 9: Subtree locks |
+| 3rd | `PerformMoveLocked` | Lock held for O(n) descendants causes timeouts | Phase 9: Batch updates |
+
+All three are documented in the design's Performance Optimizations section. The question of whether optimization is required before or after extraction is now resolved: **after** (Phase 9+).
+
+---
+
+## 9. Final Recommendation
+
+### Approved With Changes
+
+The design is approved for implementation with the following required changes:
+
+| Priority | Action Item | Category |
+|----------|-------------|----------|
+| **P0** | Add Phase 9 for hierarchical locking to phase list | Scope |
+| **P0** | Move `DeleteOfType`/`DeleteOfTypes` to Facade | Design |
+| **P0** | Add lock contract documentation requirement to each service | Process |
+| **P1** | Add git checkpoint strategy to regression protocol | Process |
+| **P1** | Clarify facade permanence in design document | Documentation |
+| **P1** | Add "NPoco first" constraint to implementation notes | Documentation |
+| **P2** | Fix phase gate test filter commands | Documentation |
+| **P2** | Add API layer impact note (no changes needed) | Documentation |
+
+### Implementation Ready
+
+Once the above changes are incorporated into the design document, implementation can proceed. The phased approach with test gates provides good risk mitigation for a refactoring of this scope.
+
+---
+
+## Appendix A: Files Created During Review
+
+| File | Purpose |
+|------|---------|
+| `tests/.../Testing/ContentServiceBenchmarkBase.cs` | Benchmark infrastructure base class |
+
+## Appendix B: Key Source Files Analyzed
+
+| File | Lines | Purpose |
+|------|-------|---------|
+| `src/Umbraco.Core/Services/ContentService.cs` | 3823 | Current monolithic implementation |
+| `src/Umbraco.Core/Services/IContentPublishingService.cs` | 57 | Existing API-layer service (no collision) |
+| `tests/.../Services/ContentServicePerformanceTest.cs` | 280 | Existing benchmark pattern |
+| `tests/.../Testing/UmbracoIntegrationTestWithContent.cs` | 83 | Integration test base |
+| `tests/Umbraco.Tests.Benchmarks/*.cs` | Various | BenchmarkDotNet project (not suitable) |
+
+## Appendix C: Lock Inventory Summary
+
+**Current ContentService Lock Distribution:**
+
+| Lock Type | Count | Operations |
+|-----------|-------|------------|
+| `ReadLock(ContentTree)` | 31 | Get*, Count*, Has*, IsPath*, RecycleBinSmells |
+| `WriteLock(ContentTree)` | 27 | Save, Delete, Publish, Unpublish, Move, Copy, Sort |
+
+**Post-Refactoring Distribution (estimated):**
+
+| Service | ReadLocks | WriteLocks |
+|---------|-----------|------------|
+| ContentCrudService | 8 | 4 |
+| ContentQueryService | 12 | 0 |
+| ContentVersionService | 4 | 3 |
+| ContentMoveService | 2 | 8 |
+| ContentPublishOperationService | 5 | 10 |
+| ContentPermissionManager | 0 | 2 |
+| ContentBlueprintManager | 2 | 4 |
diff --git a/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-3.md b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-3.md
new file mode 100644
index 0000000000..54fe34ead9
--- /dev/null
+++ b/docs/plans/2025-12-19-contentservice-refactor-design-critical-review-3.md
@@ -0,0 +1,669 @@
+# Critical Architectural Review: ContentService Refactoring Design v1.6
+
+**Reviewed Document:** `docs/plans/2025-12-19-contentservice-refactor-design.md`
+**Review Date:** 2025-12-20
+**Reviewer Role:** Senior Principal Software Architect
+**Document Revision:** 1.6 (post-critical-review changes applied)
+**Review Revision:** 3.0
+
+---
+
+## Executive Summary
+
+The ContentService refactoring design v1.6 is **approved with changes**. The design has matured through two prior reviews and addresses the core architectural challenges. This review identifies remaining refinements and documents resolutions for all outstanding issues.
+
+### Resolution Summary
+
+| Issue | Decision |
+|-------|----------|
+| Facade permanence | Keep facade, mark for future deprecation |
+| Regression threshold | Add automated guard script |
+| Cross-service failures | Add failure mode documentation |
+| Phase 9 scope | Split into sub-phases 9a-9d |
+| Phase 0 deliverables | Add test/benchmark file creation |
+| ContentServiceBase testing | Add unit tests |
+| Async expansion | Defer to future initiative |
+| Rollback triggers | Document for future reference (not required) |
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- **Mature design** - Two prior reviews have addressed major structural issues (naming, transactions, method mapping)
+- **Comprehensive documentation** - Lock contracts, notification matrix, 80+ method mapping all present
+- **Risk-conscious phasing** - Clear separation of extraction (0-8), locking (9), optimization (10+)
+- **Test-first approach** - 15 targeted tests + 33 benchmarks with phase gates
+- **Architectural alignment** - Follows Umbraco Core patterns (interface-first, notification system, scoping)
+
+### Issues Addressed in This Review
+
+| Category | Severity | Issue | Resolution |
+|----------|----------|-------|------------|
+| Strategic | Medium | Facade permanence | Future deprecation noted |
+| Operational | Medium | Manual regression threshold | Automated guard added |
+| Technical | Low-Medium | Cross-service failure modes | Documentation added |
+| Process | Low | Phase 9 scope | Split into sub-phases |
+
+---
+
+## 2. Critical Issues and Resolutions
+
+### 2.1 Facade Deprecation Strategy
+
+**Issue:** The design declared `IContentService` as "permanent public API" with no deprecation path, creating indefinite dual-maintenance burden.
+
+**Resolution:** The facade remains the stable public API for this refactoring but will be marked for future deprecation.
+
+**Required Design Update:**
+
+```markdown
+### Facade Deprecation Strategy
+
+> The `IContentService` interface and its facade implementation remain the **stable public API**
+> for this refactoring initiative. External consumers should continue using `IContentService`.
+>
+> **Future Deprecation:** In a future major version, `IContentService` will be marked as
+> `[Obsolete]` with guidance to migrate to granular services (`IContentCrudService`,
+> `IContentPublishOperationService`, etc.). The deprecation timeline will be announced
+> separately and will include:
+> - Minimum 2 major versions warning period
+> - Migration guide documentation
+> - Analyzer rules to identify usage patterns
+>
+> For now, the granular services are available for:
+> - Internal Umbraco code
+> - Advanced scenarios requiring fine-grained control
+> - Early adopters willing to accept API changes
+```
+
+---
+
+### 2.2 Automated Regression Guard
+
+**Issue:** The design specified "20% degradation triggers investigation (manual, not automated)" which risks regressions slipping through unnoticed.
+
+**Resolution:** Add an automated guard script to the phase gate process.
+
+**Required Design Update - Add to "Benchmark Execution Commands" section:**
+
+```markdown
+### Automated Regression Detection
+
+Add this script to CI or use at each phase gate:
+
+```bash
+#!/bin/bash
+# regression-guard.sh - Fails if any benchmark regresses >20%
+
+set -e
+
+BASELINE_FILE="${1:-baseline.json}"
+CURRENT_FILE="${2:-current.json}"
+THRESHOLD=${3:-20}
+
+if [ ! -f "$BASELINE_FILE" ] || [ ! -f "$CURRENT_FILE" ]; then
+ echo "Usage: regression-guard.sh [threshold]"
+ exit 1
+fi
+
+# Calculate regressions and count violations
+REGRESSION_COUNT=$(jq -s --argjson threshold "$THRESHOLD" '
+ .[0].results as $base |
+ .[1].results |
+ to_entries |
+ map(
+ select(
+ $base[.key] != null and
+ ((.value.elapsedMs - $base[.key].elapsedMs) / $base[.key].elapsedMs * 100) > $threshold
+ ) |
+ {
+ name: .key,
+ baseline: $base[.key].elapsedMs,
+ current: .value.elapsedMs,
+ change: (((.value.elapsedMs - $base[.key].elapsedMs) / $base[.key].elapsedMs * 100) | . * 10 | round / 10)
+ }
+ )
+' "$BASELINE_FILE" "$CURRENT_FILE" | jq 'length')
+
+if [ "$REGRESSION_COUNT" -gt 0 ]; then
+ echo "ERROR: $REGRESSION_COUNT benchmark(s) regressed more than ${THRESHOLD}%"
+ echo ""
+ echo "Regressions detected:"
+ jq -s --argjson threshold "$THRESHOLD" '
+ .[0].results as $base |
+ .[1].results |
+ to_entries |
+ map(
+ select(
+ $base[.key] != null and
+ ((.value.elapsedMs - $base[.key].elapsedMs) / $base[.key].elapsedMs * 100) > $threshold
+ )
+ ) |
+ .[] |
+ " - \(.key): \($base[.key].elapsedMs)ms -> \(.value.elapsedMs)ms (+\(((.value.elapsedMs - $base[.key].elapsedMs) / $base[.key].elapsedMs * 100) | . * 10 | round / 10)%)"
+ ' "$BASELINE_FILE" "$CURRENT_FILE" -r
+ exit 1
+fi
+
+echo "SUCCESS: No regressions exceeding ${THRESHOLD}% threshold"
+exit 0
+```
+
+**Usage at Phase Gates:**
+
+```bash
+# After running benchmarks at a phase gate
+./regression-guard.sh baseline.json current.json 20
+
+# Returns exit code 0 if all benchmarks within threshold
+# Returns exit code 1 if any benchmark regresses >20%
+```
+```
+
+---
+
+### 2.3 Cross-Service Failure Mode Documentation
+
+**Issue:** The design documented happy-path orchestration but didn't specify failure scenarios for facade methods that coordinate multiple services.
+
+**Resolution:** Add explicit failure mode documentation.
+
+**Required Design Update - Add new section:**
+
+```markdown
+## Failure Mode Documentation
+
+### Orchestrated Operation Failure Behavior
+
+The facade methods that coordinate multiple services use ambient scope transactions. All operations within a scope are atomic - if any operation fails, the entire transaction rolls back.
+
+| Facade Method | Step 1 | Step 2 | Failure During Step 1 | Failure During Step 2 |
+|---------------|--------|--------|----------------------|----------------------|
+| `MoveToRecycleBin` | Unpublish (if published) | Move to bin | No changes persisted, content remains published | Entire operation rolls back, content remains published at original location |
+| `DeleteOfType` | Move descendants to bin | Delete type content | No changes persisted | Entire operation rolls back, descendants remain at original locations |
+| `DeleteOfTypes` | Move descendants to bin | Delete types content | No changes persisted | Entire operation rolls back, descendants remain at original locations |
+
+### Transaction Rollback Guarantees
+
+```csharp
+// Example: MoveToRecycleBin transaction boundary
+public OperationResult MoveToRecycleBin(IContent content, int userId)
+{
+ using ICoreScope scope = ScopeProvider.CreateCoreScope();
+
+ try
+ {
+ // Step 1: Unpublish if published
+ if (content.Published)
+ {
+ var unpublishResult = _publishOperationService.Unpublish(content, "*", userId);
+ if (!unpublishResult.Success)
+ {
+ // Scope NOT completed - transaction rolls back
+ return OperationResult.Failed(...);
+ }
+ }
+
+ // Step 2: Move to recycle bin
+ var moveResult = _moveService.MoveToRecycleBinInternal(content, userId);
+ if (!moveResult.Success)
+ {
+ // Scope NOT completed - Unpublish also rolls back
+ return moveResult;
+ }
+
+ scope.Complete(); // Only now does transaction commit
+ return moveResult;
+ }
+ catch (Exception)
+ {
+ // Scope disposed without Complete() - full rollback
+ throw;
+ }
+}
+```
+
+### Notification Failure Handling
+
+If a notification handler throws an exception:
+
+1. **Cancellable notifications** (`*Saving`, `*Publishing`, etc.): Operation is aborted, transaction rolls back
+2. **Post-operation notifications** (`*Saved`, `*Published`, etc.): Exception propagates, but database changes are already committed
+
+**Important:** Post-operation notification failures can leave the system in an inconsistent state where database changes are persisted but downstream effects (cache invalidation, webhooks) may be incomplete. This is existing behavior that is preserved in the refactoring.
+
+### State After Failed Operations
+
+| Scenario | Content State | Cache State | Notifications Fired |
+|----------|--------------|-------------|---------------------|
+| Unpublish fails during MoveToRecycleBin | Unchanged (published, original location) | Unchanged | `ContentUnpublishingNotification` only |
+| Move fails after successful unpublish | Unchanged (published, original location)* | Unchanged | None persisted |
+| Notification handler throws on `ContentMovedNotification` | Moved to bin | May be stale | Partial |
+
+*Due to transaction rollback, the unpublish is also reverted.
+
+### Recommended Error Handling Pattern
+
+```csharp
+// Consumer code handling orchestrated operations
+var result = contentService.MoveToRecycleBin(content, userId);
+if (!result.Success)
+{
+ // Content is guaranteed to be in original state
+ // No partial changes have been persisted
+ logger.LogWarning("MoveToRecycleBin failed: {Status}", result.OperationStatus);
+}
+```
+```
+
+---
+
+### 2.4 Phase 9 Split Into Sub-Phases
+
+**Issue:** Phase 9 (Hierarchical Locking) was described as a single phase but encompasses significant infrastructure changes with 58 lock acquisition points to migrate.
+
+**Resolution:** Split Phase 9 into sub-phases for better risk management.
+
+**Required Design Update - Replace Phase 9 in implementation order:**
+
+```markdown
+### Phase 9: Locking Optimization (Split)
+
+Phase 9 is split into sub-phases for risk management:
+
+| Sub-Phase | Focus | Gate | Benchmarks |
+|-----------|-------|------|------------|
+| 9a | Lock hierarchy design + scope infrastructure changes | Design reviewed, infrastructure tests pass | - |
+| 9b | Migrate services with existing lock semantics (behavioral parity) | All tests pass, no behavioral change | - |
+| 9c | Optimize hot paths (Move, PublishBranch) with granular locks | All tests pass | **Run benchmarks** |
+| 9d | Final validation and documentation | All tests pass, lock contracts updated | **Run benchmarks** |
+
+#### Phase 9a: Lock Hierarchy Design
+
+**Deliverables:**
+- Lock hierarchy design document (path-based vs operation-based vs hybrid)
+- Scope infrastructure changes (if needed)
+- Unit tests for new locking primitives
+
+**Possible Approaches:**
+```csharp
+// Option A: Path-based locks (lock subtree only)
+scope.WriteLock(Constants.Locks.ContentTree, content.Path);
+
+// Option B: Operation-specific locks
+scope.WriteLock(Constants.Locks.ContentTreeMove);
+scope.WriteLock(Constants.Locks.ContentTreePublish);
+
+// Option C: Hybrid (operation + path)
+scope.WriteLock(Constants.Locks.ContentTreeMove, content.Path);
+```
+
+#### Phase 9b: Behavioral Parity Migration
+
+**Deliverables:**
+- Each service updated to use new lock infrastructure
+- Existing lock behavior preserved (same scope, same duration)
+- All integration tests pass without modification
+
+**Key Rule:** No optimization in this phase. Goal is to prove the new infrastructure works.
+
+#### Phase 9c: Hot Path Optimization
+
+**Deliverables:**
+- `PerformMoveLocked` optimized (batch updates, reduced lock duration)
+- `PublishBranch` optimized (subtree locks where applicable)
+- Lock contention tests added
+
+**Target Improvements:**
+- Move operations: Lock duration reduced from O(n) to O(batch)
+- Branch publish: Concurrent non-overlapping branches enabled
+
+#### Phase 9d: Validation and Documentation
+
+**Deliverables:**
+- All lock contracts in interface documentation updated
+- Performance comparison report (baseline vs post-optimization)
+- Lock contention metrics documented
+
+**Git Checkpoints:**
+```bash
+git tag phase-9a-complete -m "Lock infrastructure ready"
+git tag phase-9b-complete -m "Services migrated to new locks (parity)"
+git tag phase-9c-complete -m "Hot paths optimized"
+git tag phase-9d-complete -m "Phase 9 complete - locking optimization done"
+```
+```
+
+---
+
+### 2.5 Phase 0 Deliverables Expansion
+
+**Issue:** Phase 0 was described as "Write Tests" but didn't explicitly include benchmark file creation or baseline capture.
+
+**Resolution:** Expand Phase 0 deliverables.
+
+**Required Design Update - Replace Phase 0 details:**
+
+```markdown
+### Phase 0: Test and Benchmark Infrastructure
+
+**Deliverables Checklist:**
+
+- [ ] Create `ContentServiceRefactoringTests.cs` (15 integration tests)
+ - 2 notification ordering tests
+ - 3 sort operation tests
+ - 3 DeleteOfType tests
+ - 4 permission tests
+ - 3 transaction boundary tests
+
+- [ ] Create `ContentServiceRefactoringBenchmarks.cs` (33 benchmarks)
+ - 7 CRUD operation benchmarks
+ - 6 query operation benchmarks
+ - 7 publish operation benchmarks
+ - 8 move operation benchmarks
+ - 4 version operation benchmarks
+ - 1 baseline comparison test
+
+- [ ] Create `ContentServiceBaseTests.cs` (unit tests for shared infrastructure)
+ - Audit helper method tests
+ - Scope provider access pattern tests
+ - Logger injection tests
+
+- [ ] Run baseline capture
+ ```bash
+ dotnet test tests/Umbraco.Tests.Integration \
+ --filter "Category=Benchmark&FullyQualifiedName~ContentServiceRefactoringBenchmarks" \
+ --logger "console;verbosity=detailed" | tee benchmark-baseline.txt
+
+ # Extract JSON
+ grep -oP '\[BENCHMARK_JSON\]\K.*(?=\[/BENCHMARK_JSON\])' benchmark-baseline.txt > baseline.json
+
+ # Tag baseline commit
+ git tag phase-0-baseline -m "Baseline benchmarks captured"
+ ```
+
+- [ ] Verify all 15 tests pass against current ContentService
+- [ ] Verify all 33 benchmarks complete without error
+- [ ] Commit baseline.json to repository for comparison
+
+**Gate:** All tests pass, baseline captured, tagged commit created.
+```
+
+---
+
+### 2.6 ContentServiceBase Unit Tests
+
+**Issue:** The design introduces `ContentServiceBase` as shared infrastructure but the 15 new tests focus on behavior validation, not base class coverage.
+
+**Resolution:** Add unit tests for ContentServiceBase.
+
+**Required Design Update - Add to Phase 0 deliverables and Test Strategy section:**
+
+```markdown
+### ContentServiceBase Unit Tests
+
+Create `tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/ContentServiceBaseTests.cs`:
+
+```csharp
+[TestFixture]
+public class ContentServiceBaseTests
+{
+ // Audit helper method tests
+ [Test]
+ public void Audit_WithValidParameters_CreatesAuditEntry()
+ {
+ // Arrange
+ var auditService = Substitute.For();
+ var service = CreateTestService(auditService: auditService);
+
+ // Act
+ service.TestAudit(AuditType.Save, userId: 1, objectId: 100, message: "Test");
+
+ // Assert
+ auditService.Received(1).Write(
+ Arg.Is(1),
+ Arg.Is("Test"),
+ Arg.Any(),
+ Arg.Is(100));
+ }
+
+ [Test]
+ public void Audit_WithNullMessage_UsesDefaultMessage()
+ {
+ // Verify default audit message behavior
+ }
+
+ // Scope provider access pattern tests
+ [Test]
+ public void CreateScope_ReturnsValidCoreScope()
+ {
+ // Verify scope creation works correctly
+ }
+
+ [Test]
+ public void CreateScope_WithAmbientScope_ReusesExisting()
+ {
+ // Verify ambient scope detection
+ }
+
+ // Logger injection tests
+ [Test]
+ public void Logger_IsInjectedCorrectly()
+ {
+ // Verify logger is accessible and functional
+ }
+
+ [Test]
+ public void Logger_UsesCorrectCategoryName()
+ {
+ // Verify log category matches service type
+ }
+
+ // Repository access tests
+ [Test]
+ public void DocumentRepository_IsAccessibleWithinScope()
+ {
+ // Verify repository access pattern
+ }
+}
+```
+
+**Test Count:** 7 unit tests for ContentServiceBase infrastructure.
+
+**Updated Test Summary:**
+
+| Test File | Test Count | Purpose |
+|-----------|------------|---------|
+| `ContentServiceRefactoringTests.cs` | 15 | Integration tests for behavior validation |
+| `ContentServiceRefactoringBenchmarks.cs` | 33 | Performance benchmarks |
+| `ContentServiceBaseTests.cs` | 7 | Unit tests for shared infrastructure |
+| **Total** | **55** | |
+```
+
+---
+
+### 2.7 Async Expansion Strategy
+
+**Issue:** The design mentioned async overloads for long-running operations but interface definitions showed only `EmptyRecycleBinAsync`.
+
+**Resolution:** Async expansion is deferred to a future initiative.
+
+**Required Design Update - Replace Async Considerations section:**
+
+```markdown
+## Async Considerations
+
+### Current State
+
+Only `EmptyRecycleBinAsync` currently has an async variant. This refactoring preserves the existing async surface.
+
+### Future Async Expansion (Deferred)
+
+The following operations are candidates for async variants in a future initiative:
+
+| Operation | Reason for Async | Priority |
+|-----------|-----------------|----------|
+| `PublishBranch` | Tree traversal with many DB operations | High |
+| `DeleteOfType`/`DeleteOfTypes` | Bulk operations | Medium |
+| `Save` (batch) | Large batch operations | Medium |
+| `Copy` (recursive) | Deep copy operations | Low |
+
+**Decision:** Async expansion is out of scope for this refactoring. A separate initiative should address async patterns across all Umbraco services consistently.
+
+**Tracking:** Create issue "Async service methods initiative" post-refactoring.
+```
+
+---
+
+### 2.8 Production Rollback Triggers (Future Reference)
+
+**Issue:** No guidance for production deployment rollback decisions.
+
+**Resolution:** Document rollback triggers for future reference, but they are not required for this initiative.
+
+**Required Design Update - Add new section:**
+
+```markdown
+## Production Deployment Guidance (Future Reference)
+
+This section documents rollback considerations for production deployments. These are **not required** for this refactoring initiative but are preserved for future reference.
+
+### Rollback Trigger Indicators
+
+If deploying phases incrementally to production, consider rollback if:
+
+| Indicator | Threshold | Action |
+|-----------|-----------|--------|
+| Lock timeout rate | >5% increase | Investigate, consider pausing |
+| P99 latency | >50% degradation | Rollback to previous phase |
+| Error rate | >1% increase | Rollback immediately |
+| CPU utilization | >30% increase sustained | Investigate before proceeding |
+
+### Rollback Procedure
+
+```bash
+# Rollback to previous phase
+git checkout phase-{N-1}-complete
+
+# Rebuild and redeploy
+dotnet build -c Release
+# ... deployment steps ...
+```
+
+### Phase-Specific Risks
+
+| Phase | Risk Level | Special Considerations |
+|-------|------------|------------------------|
+| 1-3 | Low | Read-heavy, minimal locking changes |
+| 4 | Medium | Move/Copy affect tree structure |
+| 5 | High | Publishing is core functionality |
+| 6-7 | Low | Permissions and blueprints are isolated |
+| 8 | Medium | Facade wiring affects all operations |
+| 9a-9d | High | Locking changes affect concurrency |
+
+### Monitoring Recommendations
+
+For production deployments, ensure monitoring covers:
+- Content operation latency (Save, Publish, Move)
+- Lock acquisition time
+- Database connection pool utilization
+- Cache hit/miss rates
+- Notification handler execution time
+
+**Note:** This guidance is for future production deployments. The refactoring should be thoroughly tested in non-production environments before any production consideration.
+```
+
+---
+
+## 3. Alternative Architectural Approaches
+
+### Considered: Event-Sourced State Changes
+
+An alternative approach using event sourcing was considered:
+- All content mutations emit domain events
+- Repository changes become projections
+- Notifications become event handlers
+- Locking becomes optimistic concurrency
+
+**Decision:** The current approach (decomposition with existing patterns) is appropriate. Event sourcing would require a massive architectural shift that doesn't fit Umbraco's existing patterns. If Phase 9 locking optimization proves insufficient for high-concurrency scenarios, event sourcing could be revisited as a longer-term solution.
+
+---
+
+## 4. Final Recommendation
+
+### Approved With Required Changes
+
+The design is approved for implementation after incorporating the changes documented in this review.
+
+### Required Changes Summary
+
+| Priority | Change | Section |
+|----------|--------|---------|
+| **P0** | Add facade deprecation strategy | 2.1 |
+| **P0** | Add automated regression guard script | 2.2 |
+| **P0** | Add failure mode documentation | 2.3 |
+| **P0** | Split Phase 9 into 9a-9d | 2.4 |
+| **P0** | Expand Phase 0 deliverables | 2.5 |
+| **P1** | Add ContentServiceBase unit tests | 2.6 |
+| **P1** | Document async expansion as future work | 2.7 |
+| **P2** | Add production rollback guidance | 2.8 |
+
+### Implementation Readiness
+
+Once the above changes are incorporated into the design document (resulting in version 1.7), implementation can proceed with Phase 0.
+
+---
+
+## Appendix A: Review History
+
+| Review | Date | Key Issues | Resolution |
+|--------|------|------------|------------|
+| 1.0 | 2025-12-19 | Naming collision, transaction boundaries, method mapping | Addressed in v1.1-1.3 |
+| 2.0 | 2025-12-20 | Lock contention, benchmark infrastructure, Phase 9 scope | Addressed in v1.4-1.6 |
+| 3.0 | 2025-12-20 | Facade strategy, regression automation, failure modes | This review |
+
+## Appendix B: Cumulative Issue Tracker
+
+| Issue | Review Identified | Resolution | Design Version |
+|-------|------------------|------------|----------------|
+| Naming collision | 1.0 | Renamed to IContentPublishOperationService | 1.1 |
+| Transaction boundaries | 1.0 | Ambient scope pattern documented | 1.2 |
+| Method mapping | 1.0 | Complete 80+ method mapping | 1.2 |
+| Public/internal classification | 1.0 | Query and Versioning promoted to public | 1.2 |
+| Notification matrix | 1.0 | Matrix added | 1.3 |
+| Lock contention | 2.0 | Deferred to Phase 9 | 1.5 |
+| Benchmark infrastructure | 2.0 | Integration test pattern | 1.5 |
+| Git checkpoints | 2.0 | Tagging convention added | 1.6 |
+| Facade permanence | 2.0 | Future deprecation noted | **1.7** |
+| Regression automation | 3.0 | Guard script added | **1.7** |
+| Failure modes | 3.0 | Documentation added | **1.7** |
+| Phase 9 scope | 3.0 | Split into 9a-9d | **1.7** |
+| Phase 0 deliverables | 3.0 | Expanded checklist | **1.7** |
+| ContentServiceBase tests | 3.0 | Unit tests added | **1.7** |
+| Async expansion | 3.0 | Deferred to future | **1.7** |
+| Rollback triggers | 3.0 | Documented for reference | **1.7** |
+
+## Appendix C: Updated Phase Structure
+
+| Phase | Description | Gate | Benchmarks |
+|-------|-------------|------|------------|
+| 0 | Test and benchmark infrastructure | All tests pass, baseline captured | **Baseline** |
+| 1 | CRUD Service | All tests pass | **Run** |
+| 2 | Query Service | All tests pass | - |
+| 3 | Version Service | All tests pass | - |
+| 4 | Move Service | All tests pass | - |
+| 5 | Publish Operation Service | All tests pass | **Run** |
+| 6 | Permission Manager | All tests pass | - |
+| 7 | Blueprint Manager | All tests pass | - |
+| 8 | Facade | Full suite passes | **Run** |
+| 9a | Lock hierarchy design | Design reviewed | - |
+| 9b | Lock migration (parity) | All tests pass | - |
+| 9c | Hot path optimization | All tests pass | **Run** |
+| 9d | Validation and documentation | All tests pass | **Run** |
+| 10+ | Performance optimization | Per-optimization | Per-optimization |
+
+---
+
+*End of Critical Architectural Review v3.0*
diff --git a/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-1.md b/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-1.md
new file mode 100644
index 0000000000..299e0a9df2
--- /dev/null
+++ b/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-1.md
@@ -0,0 +1,349 @@
+# Critical Implementation Review: ContentService Phase 0 Implementation Plan
+
+**Date**: 2025-12-20
+**Reviewer**: Claude (Critical Implementation Review)
+**Document Reviewed**: `docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md`
+**Status**: Approve with Changes
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- **Well-structured incremental tasks** with clear commit boundaries and verification steps
+- **Comprehensive test coverage** for identified gaps (15 integration tests + 33 benchmarks)
+- **Good use of existing infrastructure** (`UmbracoIntegrationTestWithContent`, `ContentServiceBenchmarkBase`)
+- **Proper notification handler isolation** using static state with thread-safe locking
+- **Clear test naming** following the `Method_Scenario_ExpectedBehavior` convention
+
+### Major Concerns
+
+1. **Missing `[NonParallelizable]` attribute** risks test flakiness due to static state sharing
+2. **Incorrect using directive instruction** in Task 6 (references infrastructure scope when base class already provides access)
+3. **Non-portable shell commands** in Task 10 (`grep -oP` is GNU grep-specific)
+4. **No benchmark warmup iterations** leading to JIT-skewed baseline measurements
+5. **Missing null assertions** on template retrieval causing potential `NullReferenceException`
+6. **Design document inconsistency** with Test 1 expected behavior (now verified and corrected)
+
+---
+
+## 2. Critical Issues
+
+### Issue 1: Missing `[NonParallelizable]` Attribute - Test Flakiness Risk
+
+**Location**: Task 1, line 43-49 (test class skeleton)
+
+**Description**: The `RefactoringTestNotificationHandler` uses static mutable state (`_notificationOrder` list). NUnit can run tests in parallel by default. Without `[NonParallelizable]`, concurrent tests will corrupt the shared notification list.
+
+**Why it matters**: Random test failures in CI will undermine confidence in the refactoring safety net.
+
+**Fix**: Add `[NonParallelizable]` attribute to the test class:
+```csharp
+[TestFixture]
+[NonParallelizable] // ← ADD THIS
+[UmbracoTest(
+ Database = UmbracoTestOptions.Database.NewSchemaPerTest,
+ PublishedRepositoryEvents = true,
+ WithApplication = true,
+ Logger = UmbracoTestOptions.Logger.Console)]
+internal sealed class ContentServiceRefactoringTests : UmbracoIntegrationTestWithContent
+```
+
+---
+
+### Issue 2: Incorrect Using Directive in Task 6
+
+**Location**: Task 6, Step 1 (lines 863-867)
+
+**Description**: The plan instructs adding `using Umbraco.Cms.Infrastructure.Scoping;` but `ScopeProvider` is already accessible via the `UmbracoIntegrationTestWithContent` base class. Adding this directive is unnecessary and could cause confusion about scope ownership.
+
+**Why it matters**: Misleading instructions waste implementation time and create confusion about the scoping architecture.
+
+**Fix**: Remove the instruction to add the using directive entirely. The test code should work as-is since `ScopeProvider` is inherited from the base class.
+
+---
+
+### Issue 3: Non-Portable Shell Commands in Task 10
+
+**Location**: Task 10, Step 2 (lines 2291-2293)
+
+**Description**: The command `grep -oP '\[BENCHMARK_JSON\]\K.*(?=\[/BENCHMARK_JSON\])'` uses Perl regex (`-P`) which is GNU grep-specific. This will fail on:
+- macOS (uses BSD grep)
+- Windows (no native grep)
+- Alpine Linux Docker containers (uses BusyBox grep)
+
+**Why it matters**: CI/CD pipelines and developers on macOS/Windows cannot capture baselines.
+
+**Fix**: Replace with portable alternative:
+
+```bash
+# Option A: sed (POSIX-compliant)
+sed -n 's/.*\[BENCHMARK_JSON\]\(.*\)\[\/BENCHMARK_JSON\].*/\1/p' benchmark-*.txt > docs/plans/baseline-phase0.json
+
+# Option B: Python (cross-platform)
+python3 -c "
+import re, sys
+for line in sys.stdin:
+ m = re.search(r'\[BENCHMARK_JSON\](.*)\[/BENCHMARK_JSON\]', line)
+ if m: print(m.group(1))
+" < benchmark-*.txt > docs/plans/baseline-phase0.json
+```
+
+---
+
+### Issue 4: No Benchmark Warmup Iterations
+
+**Location**: `ContentServiceBenchmarkBase.cs`, lines 58-64
+
+**Description**: The `MeasureAndRecord` method immediately runs the action and records timing. JIT compilation, database connection pooling, and cache warming occur during the first run, skewing results.
+
+**Why it matters**: Baseline metrics will include warmup overhead, making comparison with post-refactoring runs unreliable. First runs can be 2-10x slower than steady-state.
+
+**Fix**: Update `MeasureAndRecord` to include warmup:
+
+```csharp
+protected long MeasureAndRecord(string name, int itemCount, Action action, bool skipWarmup = false)
+{
+ // Warmup iteration: triggers JIT compilation, warms connection pool and caches.
+ // Skipped for destructive operations that would fail on second execution.
+ if (!skipWarmup)
+ {
+ action();
+ }
+
+ // Measured iteration
+ var sw = Stopwatch.StartNew();
+ action();
+ sw.Stop();
+
+ RecordBenchmark(name, sw.ElapsedMilliseconds, itemCount);
+ return sw.ElapsedMilliseconds;
+}
+```
+
+For destructive operations (Delete, EmptyRecycleBin), use `skipWarmup: true` and provide separate warmup content manually in the test.
+
+---
+
+### Issue 5: Missing Null Assertion on Template Retrieval
+
+**Location**: Task 4, Step 1 (line 515); Task 4, Step 3 (line 570); Task 4, Step 5 (lines 614-622)
+
+**Description**: The code uses `FileService.GetTemplate("defaultTemplate")!` with a null-forgiving operator. If the template doesn't exist, the test will throw a cryptic `NullReferenceException` deep in content creation rather than failing fast with a clear message.
+
+**Why it matters**: Test failures will be harder to diagnose; developers will waste time investigating null reference exceptions.
+
+**Fix**: Add explicit assertion:
+```csharp
+var template = FileService.GetTemplate("defaultTemplate");
+Assert.That(template, Is.Not.Null, "Default template must exist for test setup");
+var childContentType = ContentTypeBuilder.CreateSimpleContentType(
+ "childType", "Child Type", defaultTemplateId: template.Id);
+```
+
+---
+
+### Issue 6: Design Document Inconsistency - Test 1 Expected Behavior (VERIFIED)
+
+**Location**: Design document lines 1211-1217 vs. Implementation plan Task 2
+
+**Description**: The design document previously stated that `MoveToRecycleBin` fires `ContentUnpublishingNotification` and `ContentUnpublishedNotification` before move notifications.
+
+**Verification**: Source code analysis of `ContentService.cs` lines 2457-2461 confirms:
+
+```csharp
+// if it's published we may want to force-unpublish it - that would be backward-compatible... but...
+// making a radical decision here: trashing is equivalent to moving under an unpublished node so
+// it's NOT unpublishing, only the content is now masked - allowing us to restore it if wanted
+// if (content.HasPublishedVersion)
+// { }
+```
+
+**Confirmed Behavior**: MoveToRecycleBin fires ONLY:
+1. `ContentMovingToRecycleBinNotification` (cancellable)
+2. `ContentMovedToRecycleBinNotification`
+
+**NO unpublish notifications are fired.** Content is "masked" not "unpublished".
+
+**Fix**: The design document Test 1 specification should be corrected to:
+
+```markdown
+**Test 1: MoveToRecycleBin_PublishedContent_FiresNotificationsInCorrectOrder**
+
+Verifies that for published content, `MoveToRecycleBin` fires notifications in order:
+1. `ContentMovingToRecycleBinNotification`
+2. `ContentMovedToRecycleBinNotification`
+
+> **Note:** MoveToRecycleBin does NOT fire unpublish notifications. As per the design in
+> `ContentService.cs` (lines 2457-2461): "trashing is equivalent to moving under an unpublished
+> node so it's NOT unpublishing, only the content is now masked - allowing us to restore it if wanted."
+```
+
+The implementation plan (Task 2) is **correct** - the design document was incorrect.
+
+---
+
+## 3. Minor Issues & Improvements
+
+### 3.1 Benchmark Class Should Have `[NonParallelizable]` Too
+
+**Location**: Task 7 (benchmark class)
+
+The benchmark class should also be non-parallelizable to avoid database contention during performance measurements.
+
+```csharp
+[TestFixture]
+[NonParallelizable] // ← ADD THIS
+[UmbracoTest(...)]
+[Category("Benchmark")]
+[Category("LongRunning")]
+internal sealed class ContentServiceRefactoringBenchmarks : ContentServiceBenchmarkBase
+```
+
+---
+
+### 3.2 Test 15 Stale Reference Comment
+
+**Location**: Task 6, Test 15 (lines 960-993)
+
+The test modifies a content object inside a scope, then re-fetches after rollback. The stale `content` reference could cause confusion. Add clarifying comment:
+
+```csharp
+// Note: The `content` variable still reflects the in-transaction state.
+// We must re-fetch from database to verify rollback.
+var afterRollback = ContentService.GetById(contentId);
+```
+
+---
+
+### 3.3 Hardcoded Permission Characters
+
+**Location**: Tests 9-12 (Task 5)
+
+Tests use hardcoded permission characters like `"F"`, `"U"`, `"P"`. Consider using constants for maintainability:
+
+```csharp
+// Current
+ContentService.SetPermission(content, "F", new[] { adminGroup.Id });
+
+// Improved (if constants exist)
+ContentService.SetPermission(content, ActionBrowse.ActionLetter.ToString(), new[] { adminGroup.Id });
+```
+
+---
+
+### 3.4 Benchmark JSON Output Should Include Git Commit Hash
+
+**Location**: `ContentServiceBenchmarkBase.cs`, `OutputBenchmarkResults` method
+
+The JSON output doesn't include the git commit hash, making it harder to correlate results with code versions.
+
+**Suggested Enhancement**:
+```csharp
+var output = new {
+ commit = Environment.GetEnvironmentVariable("GIT_COMMIT") ?? "unknown",
+ timestamp = DateTime.UtcNow,
+ results = _results
+};
+var json = JsonSerializer.Serialize(output, ...);
+```
+
+---
+
+### 3.5 Consider `TestCaseSource` for DeleteOfType Tests
+
+Tests 6, 7, 8 have significant setup duplication for creating content types. Consider extracting shared setup or using `[TestCaseSource]` for parameterized tests in future iterations.
+
+---
+
+## 4. Questions Resolved
+
+| Question | Resolution |
+|----------|------------|
+| Test 1 Behavior | **Verified via source code**: MoveToRecycleBin does NOT fire unpublish notifications. Content is "masked" not "unpublished". |
+| Warmup Strategy | **Recommended**: Single warmup iteration before measurement; `skipWarmup` parameter for destructive operations. |
+| CI Integration | **Confirmed**: Benchmarks run only at phase gates, skipped on PRs via `[LongRunning]` category. |
+
+---
+
+## 5. Summary of Required Changes
+
+### Must Fix Before Execution
+
+| # | Issue | Location | Fix |
+|---|-------|----------|-----|
+| 1 | Missing `[NonParallelizable]` | Task 1, line 43 | Add attribute to test class |
+| 2 | Incorrect using directive | Task 6, Step 1 | Remove instruction entirely |
+| 3 | Non-portable `grep -oP` | Task 10, Step 2 | Replace with `sed` or Python |
+| 4 | No benchmark warmup | `ContentServiceBenchmarkBase.cs` | Add warmup iteration to `MeasureAndRecord` |
+| 5 | Missing null assertion | Tasks 4 (3 locations) | Add `Assert.That(template, Is.Not.Null, ...)` |
+
+### Should Fix
+
+| # | Issue | Location | Fix |
+|---|-------|----------|-----|
+| 6 | Design doc Test 1 spec | Design document lines 1211-1217 | Correct to match actual behavior |
+| 7 | Benchmark class parallelization | Task 7 | Add `[NonParallelizable]` |
+
+### Optional Improvements
+
+| # | Issue | Location | Suggestion |
+|---|-------|----------|------------|
+| 8 | Stale reference clarity | Task 6, Test 15 | Add clarifying comment |
+| 9 | Hardcoded permissions | Task 5 | Use constants if available |
+| 10 | Git commit in JSON | `ContentServiceBenchmarkBase.cs` | Include commit hash in output |
+
+---
+
+## 6. Final Recommendation
+
+**Approve with Changes**
+
+The Phase 0 implementation plan is well-structured and addresses legitimate test coverage gaps. The 5 required fixes are straightforward and don't require architectural changes. Once applied, this plan will provide a reliable safety net for the ContentService refactoring.
+
+**Gate Criteria After Fixes**:
+- [ ] All 15 integration tests pass
+- [ ] All 33 benchmarks complete without error
+- [ ] Baseline JSON captured with portable command
+- [ ] `phase-0-baseline` git tag created
+
+---
+
+## Appendix: Verified Source Code References
+
+### MoveToRecycleBin Notification Sequence
+
+**File**: `src/Umbraco.Core/Services/ContentService.cs`
+**Lines**: 2436-2479
+
+```csharp
+public OperationResult MoveToRecycleBin(IContent content, int userId = Constants.Security.SuperUserId)
+{
+ // ... setup ...
+
+ var movingToRecycleBinNotification =
+ new ContentMovingToRecycleBinNotification(moveEventInfo, eventMessages);
+ if (scope.Notifications.PublishCancelable(movingToRecycleBinNotification))
+ {
+ scope.Complete();
+ return OperationResult.Cancel(eventMessages);
+ }
+
+ // if it's published we may want to force-unpublish it - that would be backward-compatible... but...
+ // making a radical decision here: trashing is equivalent to moving under an unpublished node so
+ // it's NOT unpublishing, only the content is now masked - allowing us to restore it if wanted
+ // if (content.HasPublishedVersion)
+ // { }
+
+ PerformMoveLocked(content, Constants.System.RecycleBinContent, null, userId, moves, true);
+
+ scope.Notifications.Publish(
+ new ContentMovedToRecycleBinNotification(moveInfo, eventMessages).WithStateFrom(
+ movingToRecycleBinNotification));
+
+ // ...
+}
+```
+
+**Conclusion**: The commented-out `if (content.HasPublishedVersion)` block confirms the deliberate design decision to NOT unpublish content when moving to recycle bin.
diff --git a/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-2.md b/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-2.md
new file mode 100644
index 0000000000..85201f1ca2
--- /dev/null
+++ b/docs/plans/2025-12-19-contentservice-refactor-phase0-implementation-critical-review-2.md
@@ -0,0 +1,419 @@
+# Critical Implementation Review: ContentService Refactoring Phase 0 (Review 2)
+
+**Document:** `docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md` (v1.1)
+**Reviewer:** Claude (Critical Implementation Review)
+**Date:** 2025-12-20
+**Status:** Major Revisions Required
+
+---
+
+## Executive Summary
+
+This review identifies a critical benchmark measurement bug and several moderate issues requiring resolution before Phase 0 execution. The warmup logic in non-destructive benchmarks corrupts measurements by operating on mutated state rather than fresh data.
+
+**Verdict:** Plan requires v1.2 revision before execution.
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- Well-structured task breakdown with atomic commits following conventional commit format
+- Proper use of existing test infrastructure (`UmbracoIntegrationTestWithContent`, `ContentServiceBenchmarkBase`)
+- Previous review feedback incorporated (`[NonParallelizable]`, null assertions, POSIX-compliant sed)
+- Good test coverage across notification ordering, sort, delete, permission, and transaction boundary scenarios
+- Warmup with `skipWarmup` parameter for destructive benchmarks
+
+### Major Concerns
+
+- **Critical warmup logic bug** in non-destructive benchmarks invalidates performance measurements
+- Benchmark `MeasureAndRecord` overload lacks documentation about warmup behavior
+- Inconsistent benchmark data sizes prevent meaningful cross-benchmark comparisons
+- Silent failure on missing baseline JSON masks infrastructure problems
+
+---
+
+## 2. Critical Issues
+
+### 2.1 Warmup Logic Corrupts Benchmark Measurements
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | CRITICAL |
+| **Location** | Task 7 - All non-destructive benchmarks using `MeasureAndRecord` |
+| **Decision** | Warmup must use completely separate data; measured run uses fresh identical data |
+
+**Description:**
+
+The warmup executes the same action on the same data, but for benchmarks that mutate state, this means the measured run operates on different data than intended.
+
+**Example - `Benchmark_Save_SingleItem` (lines 1116-1126):**
+
+```csharp
+var content = ContentBuilder.CreateSimpleContent(ContentType, "BenchmarkSingle", -1);
+MeasureAndRecord("Save_SingleItem", 1, () =>
+{
+ ContentService.Save(content); // Warmup: INSERT (assigns ID)
+ // Measured: UPDATE (different operation!)
+});
+```
+
+**Impact:** Benchmarking UPDATE performance when INSERT performance is intended. Affects:
+- `Benchmark_Save_SingleItem`, `Benchmark_Save_BatchOf100`, `Benchmark_Save_BatchOf1000`
+- All `Benchmark_Publish_*` variants
+- Any benchmark where the action mutates setup data
+
+**Required Fix:**
+
+All non-destructive benchmarks must create throwaway data for warmup, then fresh identical data for measurement:
+
+```csharp
+public void Benchmark_Save_SingleItem()
+{
+ // Warmup with throwaway content (triggers JIT, warms caches)
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_SingleItem", -1);
+ ContentService.Save(warmupContent);
+
+ // Measured run with fresh, identical setup
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "BenchmarkSingle", -1);
+ var sw = Stopwatch.StartNew();
+ ContentService.Save(content);
+ sw.Stop();
+ RecordBenchmark("Save_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Id, Is.GreaterThan(0));
+}
+```
+
+**Benchmarks Requiring This Pattern:** 1-5, 8-20, 21-27, 29-30 (all non-destructive)
+
+---
+
+### 2.2 MeasureAndRecord Overload Missing Documentation
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | MEDIUM |
+| **Location** | `ContentServiceBenchmarkBase.cs` lines 89-96 |
+| **Decision** | Document that this overload is intended for read-only operations |
+
+**Description:**
+
+The `Func` overload of `MeasureAndRecord` has no warmup support:
+
+```csharp
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+{
+ var sw = Stopwatch.StartNew();
+ var result = func();
+ sw.Stop();
+ RecordBenchmark(name, sw.ElapsedMilliseconds, itemCount);
+ return result;
+}
+```
+
+**Required Fix:**
+
+Add documentation comment:
+
+```csharp
+///
+/// Measures and records a benchmark, returning the result of the function.
+///
+///
+/// This overload is intended for READ-ONLY operations that do not need warmup.
+/// For write operations that modify state, use the Action overload with explicit
+/// warmup data separation.
+///
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+```
+
+---
+
+### 2.3 Benchmark 31 Index Out of Range Risk
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | MEDIUM |
+| **Location** | Task 7, Benchmark 31 - `Benchmark_Rollback_ToVersion` (lines 1897-1915) |
+| **Decision** | Add defensive assertion and use relative indexing |
+
+**Description:**
+
+```csharp
+var versions = ContentService.GetVersions(content.Id).ToList();
+var targetVersionId = versions[5].VersionId; // Assumes at least 6 versions exist
+```
+
+**Required Fix:**
+
+```csharp
+var versions = ContentService.GetVersions(content.Id).ToList();
+Assert.That(versions.Count, Is.GreaterThanOrEqualTo(6), "Need at least 6 versions for rollback test");
+var targetVersionId = versions[versions.Count / 2].VersionId; // Middle version
+```
+
+---
+
+### 2.4 Sort Tests Assume Specific Initial Sort Order
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | MEDIUM |
+| **Location** | Task 3 - Tests 3-5 (lines 385-508) |
+| **Decision** | Add explicit verification of initial state |
+
+**Description:**
+
+Tests assume `Subpage`, `Subpage2`, `Subpage3` have specific sort orders that can be meaningfully reversed. The base class creates them sequentially, but sort orders are not explicitly verified.
+
+**Required Fix:**
+
+Add at the start of each sort test:
+
+```csharp
+// Verify initial sort order assumption
+Assert.That(child1.SortOrder, Is.LessThan(child2.SortOrder), "Setup: child1 before child2");
+Assert.That(child2.SortOrder, Is.LessThan(child3.SortOrder), "Setup: child2 before child3");
+```
+
+---
+
+### 2.5 Silent Failure on Missing Baseline JSON
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | MEDIUM |
+| **Location** | Task 10, Step 2 |
+| **Decision** | Fail loudly instead of silent fallback |
+
+**Description:**
+
+Current command silently creates empty JSON if no benchmarks found:
+
+```bash
+sed -n '...' benchmark-*.txt > docs/plans/baseline-phase0.json || echo "[]" > docs/plans/baseline-phase0.json
+```
+
+**Required Fix:**
+
+```bash
+# Extract JSON results - fail if no benchmarks found
+BENCHMARK_OUTPUT=$(sed -n 's/.*\[BENCHMARK_JSON\]\(.*\)\[\/BENCHMARK_JSON\].*/\1/p' benchmark-*.txt)
+if [ -z "$BENCHMARK_OUTPUT" ]; then
+ echo "ERROR: No benchmark results found in output. Check test execution." >&2
+ exit 1
+fi
+echo "$BENCHMARK_OUTPUT" > docs/plans/baseline-phase0.json
+```
+
+---
+
+## 3. Minor Issues & Improvements
+
+### 3.1 Inconsistent Benchmark Data Sizes
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | LOW |
+| **Decision** | Standardize to Small (10), Medium (100), Large (1000) |
+
+**Required Changes:**
+
+| Benchmark | Current | New | Change |
+|-----------|---------|-----|--------|
+| `Benchmark_Delete_WithDescendants` | 50 | 100 | +50 |
+| `Benchmark_Count_ByContentType` | 500 | 1000 | +500 |
+| `Benchmark_CountDescendants` | 500 | 1000 | +500 |
+| `Benchmark_Publish_BatchOf50` | 50 | 100 | +50 |
+| `Benchmark_PublishBranch_ShallowTree` | 20 | 100 | +80 |
+| `Benchmark_PerformScheduledPublish` | 50 | 100 | +50 |
+| `Benchmark_Move_WithDescendants` | 50 | 100 | +50 |
+| `Benchmark_MoveToRecycleBin_LargeTree` | 100 | 1000 | +900 |
+| `Benchmark_Copy_Recursive` | 50 | 100 | +50 |
+| `Benchmark_GetVersions` | 50 | 100 | +50 |
+| `Benchmark_GetVersionsSlim` | 50 | 100 | +50 |
+| `Benchmark_DeleteVersions` | 50 | 100 | +50 |
+
+**Note:** Rename `Benchmark_Publish_BatchOf50` to `Benchmark_Publish_BatchOf100` after resize.
+
+---
+
+### 3.2 Document Permission Accumulation Behavior
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | LOW |
+| **Location** | Task 5, Test 10 |
+| **Decision** | Add explicit documentation of expected behavior |
+
+**Required Fix:**
+
+```csharp
+///
+/// Test 10: Verifies multiple SetPermission calls accumulate permissions for a user group.
+///
+///
+/// Expected behavior: SetPermission assigns permissions per-permission-type, not per-entity.
+/// Calling SetPermission("F", ...) then SetPermission("U", ...) results in both F and U
+/// permissions being assigned. Each call only replaces permissions of the same type.
+///
+[Test]
+public void SetPermission_MultiplePermissionsForSameGroup()
+```
+
+---
+
+### 3.3 Test 13 Unused Variables
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | LOW |
+| **Location** | Task 6, Test 13 (lines 914-944) |
+
+**Description:**
+
+Variables `id1` and `id2` are captured but never used after the scope ends.
+
+**Suggested Fix:**
+
+Either remove the variables or add a clarifying comment:
+
+```csharp
+// Note: IDs are captured for debugging but cannot be used after rollback
+// since they were assigned within the rolled-back transaction
+var id1 = content1.Id;
+var id2 = content2.Id;
+```
+
+---
+
+### 3.4 Missing Category for Integration Tests
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | LOW |
+| **Location** | `ContentServiceRefactoringTests.cs` |
+
+**Suggested Fix:**
+
+Add category for easier filtering:
+
+```csharp
+[TestFixture]
+[NonParallelizable]
+[Category("Refactoring")] // Add this
+[UmbracoTest(...)]
+```
+
+---
+
+### 3.5 Benchmark 33 Documentation
+
+| Attribute | Value |
+|-----------|-------|
+| **Severity** | LOW |
+| **Location** | Lines 1952-1991 |
+
+**Observation:**
+
+`Benchmark_BaselineComparison` manually times and calls `RecordBenchmark` instead of using `MeasureAndRecord`. This is intentional (multi-step composite), but a comment explaining why would improve clarity.
+
+---
+
+## 4. Clarification Questions (Resolved)
+
+| Question | Resolution |
+|----------|------------|
+| Benchmark warmup strategy | Warmup should use completely separate data |
+| Permission accumulation | Test should explicitly document this as expected behavior |
+| Baseline JSON extraction | Should fail loudly on missing data |
+| Data consistency | Data should always be the same for consistency |
+
+---
+
+## 5. Summary of Required Changes for v1.2
+
+### Must Fix (Blocking)
+
+| # | Issue | Change Required |
+|---|-------|-----------------|
+| 1 | Warmup logic bug | Restructure all non-destructive benchmarks to create separate warmup data |
+| 2 | Silent baseline failure | Replace `|| echo "[]"` with explicit error and exit |
+
+### Should Fix (Before Execution)
+
+| # | Issue | Change Required |
+|---|-------|-----------------|
+| 3 | `MeasureAndRecord` docs | Add remarks about read-only usage |
+| 4 | Benchmark 31 index | Add defensive assertion, use relative indexing |
+| 5 | Sort test assumptions | Add initial state verification |
+| 6 | Data size standardization | Normalize to 10/100/1000 pattern |
+| 7 | Permission test docs | Add behavior documentation |
+
+### Consider (Polish)
+
+| # | Issue | Change Required |
+|---|-------|-----------------|
+| 8 | Test 13 unused vars | Add comment or remove |
+| 9 | Refactoring category | Add `[Category("Refactoring")]` |
+| 10 | Benchmark 33 comment | Explain manual timing |
+
+---
+
+## 6. Final Recommendation
+
+**Status: Major Revisions Required**
+
+The warmup logic bug (Issue 2.1) fundamentally invalidates benchmark measurements and must be fixed before execution. Apply all "Must Fix" and "Should Fix" changes, then re-review the updated plan.
+
+Once v1.2 is prepared with these changes, the plan will provide a solid foundation for Phase 0 test infrastructure.
+
+---
+
+## Appendix: Affected Benchmark List
+
+### Benchmarks Requiring Warmup Pattern Change
+
+These benchmarks currently use `MeasureAndRecord` with warmup enabled but operate on mutable data:
+
+1. `Benchmark_Save_SingleItem`
+2. `Benchmark_Save_BatchOf100`
+3. `Benchmark_Save_BatchOf1000`
+4. `Benchmark_GetById_Single`
+5. `Benchmark_GetByIds_BatchOf100`
+6. `Benchmark_GetPagedChildren_100Items`
+7. `Benchmark_GetPagedDescendants_DeepTree`
+8. `Benchmark_GetAncestors_DeepHierarchy`
+9. `Benchmark_Count_ByContentType`
+10. `Benchmark_CountDescendants_LargeTree`
+11. `Benchmark_HasChildren_100Nodes`
+12. `Benchmark_Publish_SingleItem`
+13. `Benchmark_Publish_BatchOf100` (renamed from BatchOf50)
+14. `Benchmark_PublishBranch_ShallowTree`
+15. `Benchmark_PublishBranch_DeepTree`
+16. `Benchmark_Unpublish_SingleItem`
+17. `Benchmark_PerformScheduledPublish`
+18. `Benchmark_GetContentSchedulesByIds_100Items`
+19. `Benchmark_Move_SingleItem`
+20. `Benchmark_Move_WithDescendants`
+21. `Benchmark_MoveToRecycleBin_Published`
+22. `Benchmark_MoveToRecycleBin_LargeTree`
+23. `Benchmark_Copy_SingleItem`
+24. `Benchmark_Copy_Recursive_100Items` (renamed from 50Items)
+25. `Benchmark_Sort_100Children`
+26. `Benchmark_GetVersions_ItemWith100Versions` (renamed from 50)
+27. `Benchmark_GetVersionsSlim_Paged`
+
+### Benchmarks Already Using `skipWarmup: true` (No Change Needed)
+
+1. `Benchmark_Delete_SingleItem`
+2. `Benchmark_Delete_WithDescendants`
+3. `Benchmark_EmptyRecycleBin_100Items`
+4. `Benchmark_Rollback_ToVersion`
+5. `Benchmark_DeleteVersions_ByDate`
+
+### Special Case (Manual Timing)
+
+1. `Benchmark_BaselineComparison` - Uses manual `Stopwatch` (correct as-is)
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-critical-review-3.md b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-critical-review-3.md
new file mode 100644
index 0000000000..61b4d1babe
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-critical-review-3.md
@@ -0,0 +1,348 @@
+# Critical Implementation Review #3: ContentService Refactoring Phase 0
+
+**Document:** `docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md`
+**Review Date:** 2025-12-20
+**Reviewer:** Claude (Critical Implementation Review Skill)
+**Plan Version Reviewed:** v1.2
+
+---
+
+## 1. Overall Assessment
+
+**Verdict: Approve with Minor Changes**
+
+The plan is well-structured and comprehensive, establishing solid test infrastructure for the ContentService refactoring. Two prior critical reviews (v1.1 and v1.2) have already addressed significant issues including warmup patterns, data standardization, and POSIX compatibility.
+
+### Strengths
+
+- **Comprehensive coverage:** 15 integration tests + 33 benchmarks + 1 unit test placeholder
+- **Well-organized tasks:** 11 tasks with clear steps and verification commands
+- **Good commit hygiene:** Atomic commits per task with conventional commit messages
+- **Proper warmup patterns:** Documented for destructive vs non-destructive benchmarks
+- **Revision history:** Transparent tracking of changes from prior reviews
+- **API validation:** All referenced APIs verified to exist:
+ - `ContentService.Sort(IEnumerable)` ✓
+ - `ContentService.RecycleBinSmells()` ✓
+ - `ContentScheduleCollection.CreateWithEntry(DateTime?, DateTime?)` ✓
+ - `PublishBranchFilter.Default` ✓
+
+### Concerns Addressed in This Review
+
+| Priority | Issue | Status |
+|----------|-------|--------|
+| MUST FIX | Variable shadowing in Test 4 | New finding |
+| MUST FIX | `ContentServiceBenchmarkBase.cs` not committed | New finding |
+| SHOULD FIX | `MeasureAndRecord` missing warmup | Escalated from v1.2 |
+| SHOULD FIX | Missing tracking mechanism for ContentServiceBaseTests | New finding |
+
+---
+
+## 2. Critical Issues
+
+### Issue #1: Variable Shadowing Causes Compilation Error
+
+**Location:** Task 3, Test 4 (lines 508-515)
+
+**Problem:** Variables `child1`, `child2`, `child3` are redeclared with `var`, causing `CS0128: A local variable named 'child1' is already defined in this scope`.
+
+```csharp
+// Lines 486-489: First declaration
+var child1 = ContentService.GetById(Subpage.Id)!;
+var child2 = ContentService.GetById(Subpage2.Id)!;
+var child3 = ContentService.GetById(Subpage3.Id)!;
+
+// Lines 509-511: ERROR - redeclares variables
+var child1 = ContentService.GetById(child1Id)!; // CS0128
+var child2 = ContentService.GetById(child2Id)!; // CS0128
+var child3 = ContentService.GetById(child3Id)!; // CS0128
+```
+
+**Impact:** Code will not compile.
+
+**Required Fix:** Remove `var` keyword on lines 509-511:
+
+```csharp
+// Re-fetch to verify persisted order
+child1 = ContentService.GetById(child1Id)!;
+child2 = ContentService.GetById(child2Id)!;
+child3 = ContentService.GetById(child3Id)!;
+```
+
+---
+
+### Issue #2: ContentServiceBenchmarkBase.cs Not Committed
+
+**Location:** Git status shows `?? tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs`
+
+**Problem:** The benchmark base class exists locally but is untracked in git. Anyone cloning the repository will have compilation failures.
+
+**Impact:** Benchmark tests will not compile for other developers.
+
+**Required Fix:** Add a prerequisite step before Task 1:
+
+```bash
+# Task 0 (Prerequisite): Commit benchmark infrastructure
+git add tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs
+git commit -m "$(cat <<'EOF'
+test: add ContentServiceBenchmarkBase infrastructure class
+
+Adds base class for ContentService performance benchmarks with:
+- RecordBenchmark() for timing capture
+- MeasureAndRecord() with warmup support
+- JSON output wrapped in [BENCHMARK_JSON] markers for extraction
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+### Issue #3: MeasureAndRecord Missing Warmup
+
+**Location:** `ContentServiceBenchmarkBase.cs` lines 89-96
+
+**Problem:** The generic `MeasureAndRecord` overload does not perform warmup, unlike the `Action` overload:
+
+```csharp
+// Current implementation - NO WARMUP
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+{
+ var sw = Stopwatch.StartNew();
+ var result = func(); // First call includes JIT overhead
+ sw.Stop();
+ RecordBenchmark(name, sw.ElapsedMilliseconds, itemCount);
+ return result;
+}
+```
+
+**Impact:** Read-only benchmarks (Benchmarks 4, 5, 8-13, 20, 29, 30) will include JIT compilation overhead in measurements.
+
+**Required Fix:** Add warmup to `MeasureAndRecord`:
+
+```csharp
+///
+/// Measures and records a benchmark, returning the result of the function.
+///
+///
+/// Performs a warmup call before measurement to trigger JIT compilation.
+/// Safe for read-only operations that can be repeated without side effects.
+///
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+{
+ // Warmup: triggers JIT compilation, warms caches
+ try { func(); } catch { /* ignore warmup errors */ }
+
+ var sw = Stopwatch.StartNew();
+ var result = func();
+ sw.Stop();
+ RecordBenchmark(name, sw.ElapsedMilliseconds, itemCount);
+ return result;
+}
+```
+
+---
+
+### Issue #4: Missing Tracking for ContentServiceBaseTests
+
+**Location:** Task 8, `ContentServiceBaseTests.cs`
+
+**Problem:** The unit tests are commented out pending Phase 1 creation of `ContentServiceBase`. There's no mechanism to ensure they get uncommented when the class is created.
+
+**Impact:** Tests could remain dormant indefinitely, providing no value.
+
+**Required Fix:** Add a tracking mechanism. Options:
+
+**Option A: Add a failing placeholder test (Recommended)**
+
+Replace the current placeholder with a test that will fail when `ContentServiceBase` exists:
+
+```csharp
+///
+/// Tracking test: Fails when ContentServiceBase is created, reminding developers
+/// to uncomment the actual tests.
+///
+[Test]
+public void ContentServiceBase_WhenCreated_UncommentTests()
+{
+ // This test exists to track when ContentServiceBase is created.
+ // When you see this test fail, uncomment all tests in this file
+ // and delete this placeholder.
+
+ var type = Type.GetType("Umbraco.Cms.Infrastructure.Services.ContentServiceBase, Umbraco.Infrastructure");
+
+ Assert.That(type, Is.Null,
+ "ContentServiceBase now exists! Uncomment the tests in this file and delete this placeholder.");
+}
+```
+
+**Option B: Add TODO comment with issue reference**
+
+Create a GitHub issue and reference it:
+
+```csharp
+// TODO: Issue #XXXXX - Uncomment tests when ContentServiceBase is created in Phase 1
+// Tests are commented out because ContentServiceBase doesn't exist yet.
+```
+
+---
+
+## 3. Minor Issues & Improvements
+
+### 3.1 Permission Test Magic Strings
+
+**Location:** Task 5, Tests 9-12
+
+**Current:** Uses magic strings for permission codes:
+```csharp
+ContentService.SetPermission(content, "F", new[] { adminGroup!.Id }); // Browse
+ContentService.SetPermission(content, "U", new[] { adminGroup.Id }); // Update
+```
+
+**Suggestion:** Document the permission codes inline or use constants:
+```csharp
+// Permission codes: F=Browse, U=Update, P=Publish
+// See Umbraco.Cms.Core.Actions for full list
+ContentService.SetPermission(content, "F", new[] { adminGroup!.Id });
+```
+
+**Priority:** Consider (low impact, improves readability)
+
+---
+
+### 3.2 Benchmark Expected Ranges
+
+**Location:** Task 7 (all benchmarks)
+
+**Current:** Benchmarks capture timing but don't document expected ranges.
+
+**Suggestion:** After initial baseline capture, add comments with rough expectations:
+```csharp
+// Baseline expectation: < 50ms (adjust after Phase 0 baseline capture)
+RecordBenchmark("Save_SingleItem", sw.ElapsedMilliseconds, 1);
+```
+
+**Priority:** Consider (helpful for future regression detection)
+
+**Note:** Per user clarification, benchmarks will NOT fail the build based on thresholds in the current phase. This may change in future phases.
+
+---
+
+### 3.3 Task 10 JSON Validation
+
+**Location:** Task 10, Step 2
+
+**Current:** Extracts JSON but doesn't validate it.
+
+**Suggestion:** Add optional validation:
+```bash
+# Optional: Validate JSON format
+if command -v jq &> /dev/null; then
+ if ! jq empty docs/plans/baseline-phase0.json 2>/dev/null; then
+ echo "WARNING: baseline-phase0.json may contain invalid JSON"
+ fi
+fi
+```
+
+**Priority:** Consider (defensive, but jq may not be available everywhere)
+
+---
+
+## 4. Questions Resolved
+
+### Q1: Baseline Thresholds
+
+**Question:** Should any benchmarks fail the build if they exceed a certain threshold?
+
+**Resolution:** No. Benchmarks currently capture metrics only. Threshold-based failures may be added in future phases.
+
+---
+
+### Q2: Async Method Coverage
+
+**Question:** Are there async versions of ContentService methods that should be benchmarked?
+
+**Resolution:**
+
+| Service | Pattern | Async Methods |
+|---------|---------|---------------|
+| `IContentService` | Synchronous | Only `EmptyRecycleBinAsync` |
+| `IContentEditingService` | Fully async | `GetAsync`, `CreateAsync`, `UpdateAsync`, `MoveAsync`, etc. |
+
+The Phase 0 plan correctly focuses on `IContentService` (the synchronous service being refactored). `IContentEditingService` is a separate API layer and not in scope for this phase.
+
+---
+
+### Q3: ContentServiceBaseTests Tracking
+
+**Question:** Should there be a tracking mechanism for the commented tests?
+
+**Resolution:** Yes. A tracking mechanism is required (see Issue #4 above).
+
+---
+
+### Q4: Base Class Properties
+
+**Question:** Are `Textpage`, `Subpage`, `Subpage2`, `Subpage3` available from the base class?
+
+**Resolution:** Yes. Verified in `UmbracoIntegrationTestWithContent.cs`:
+- `Textpage` - Root content item
+- `Subpage`, `Subpage2`, `Subpage3` - Children of Textpage, created in sequence
+- `ContentType` - The "umbTextpage" content type
+- `FileService`, `ContentTypeService` - Available via properties
+
+The v1.2 assertions verifying initial sort order are appropriate defensive programming.
+
+---
+
+## 5. Summary of Required Changes
+
+### Must Fix (Blocking)
+
+| # | Issue | Location | Fix |
+|---|-------|----------|-----|
+| 1 | Variable shadowing | Task 3, Test 4, lines 509-511 | Remove `var` keyword |
+| 2 | Untracked file | `ContentServiceBenchmarkBase.cs` | Add Task 0 to commit |
+
+### Should Fix (High Priority)
+
+| # | Issue | Location | Fix |
+|---|-------|----------|-----|
+| 3 | Missing warmup | `MeasureAndRecord` in base class | Add warmup call |
+| 4 | No tracking mechanism | Task 8, `ContentServiceBaseTests.cs` | Add tracking test or TODO |
+
+### Consider (Optional)
+
+| # | Issue | Location | Suggestion |
+|---|-------|----------|------------|
+| 5 | Magic strings | Task 5 permission tests | Add inline documentation |
+| 6 | No expected ranges | Task 7 benchmarks | Document after baseline capture |
+| 7 | No JSON validation | Task 10 | Add optional jq validation |
+
+---
+
+## 6. Final Recommendation
+
+**Approve with Minor Changes**
+
+The plan is ready for implementation after applying the four required fixes:
+
+1. **Task 3, Test 4:** Remove `var` from lines 509-511
+2. **Add Task 0:** Commit `ContentServiceBenchmarkBase.cs` before Task 1
+3. **Update `ContentServiceBenchmarkBase.cs`:** Add warmup to `MeasureAndRecord`
+4. **Task 8:** Add tracking mechanism for commented tests
+
+Once these changes are incorporated (creating v1.3 of the plan), implementation can proceed.
+
+---
+
+## Appendix: Version History
+
+| Version | Date | Reviewer | Summary |
+|---------|------|----------|---------|
+| 1.0 | 2025-12-20 | - | Initial implementation plan |
+| 1.1 | 2025-12-20 | Critical Review #1 | `[NonParallelizable]`, template null checks, POSIX sed, warmup |
+| 1.2 | 2025-12-20 | Critical Review #2 | Warmup data separation, data size standardization |
+| 1.3 | TBD | Critical Review #3 | Variable shadowing fix, commit base class, `MeasureAndRecord` warmup, tracking mechanism |
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-summary.md b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-summary.md
new file mode 100644
index 0000000000..b4a1a6418e
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation-summary.md
@@ -0,0 +1,78 @@
+# ContentService Refactoring Phase 0 Implementation Plan - Completion Summary
+
+## 1. Overview
+
+**Original Scope and Goals:**
+Phase 0 aimed to create test and benchmark infrastructure to establish baseline metrics and safety nets before the ContentService refactoring begins. The plan specified 12 tasks (Task 0-11), delivering 15 integration tests, 33 benchmarks, and 1 tracking unit test across 4 test files.
+
+**Overall Completion Status:** Fully Completed (with post-completion fixes applied)
+
+All planned tasks were executed, all test files were created, and baseline benchmarks were captured. A post-completion review identified and resolved 5 benchmark test implementation issues that were causing test failures.
+
+---
+
+## 2. Completed Items
+
+- **Task 0:** Committed `ContentServiceBenchmarkBase.cs` with warmup support for `MeasureAndRecord` methods
+- **Task 1:** Created `ContentServiceRefactoringTests.cs` skeleton with notification handler infrastructure
+- **Task 2:** Added 2 notification ordering tests for MoveToRecycleBin behavior
+- **Task 3:** Added 3 sort operation tests (IContent, IDs, notifications)
+- **Task 4:** Added 3 DeleteOfType tests (descendants, mixed types, multiple types)
+- **Task 5:** Added 4 permission tests (SetPermission, multiple permissions, permission set, multiple groups)
+- **Task 6:** Added 3 transaction boundary tests (rollback, commit, MoveToRecycleBin rollback)
+- **Task 7:** Created `ContentServiceRefactoringBenchmarks.cs` with 33 benchmarks across 5 categories
+- **Task 8:** Created `ContentServiceBaseTests.cs` with tracking test for Phase 1 detection
+- **Task 9:** Verified all 15 integration tests pass
+- **Task 10:** Captured baseline benchmarks to `docs/plans/baseline-phase0.json`
+- **Task 11:** Created git tag `phase-0-baseline` and verified all artifacts
+
+---
+
+## 3. Partially Completed or Modified Items
+
+- **Version-related benchmarks (GetVersions, GetVersionsSlim, Rollback, DeleteVersions):** Required post-completion modification. The original implementation used `Save()` to create versions, but Umbraco's versioning system requires `Publish()` to create new versions. Tests were corrected to call `Publish()` after each `Save()`.
+
+- **HasChildren benchmark:** Required post-completion modification. The counter variable was accumulating across warmup and measurement runs due to the `MeasureAndRecord` warmup pattern. Fixed by resetting the counter inside the measurement action.
+
+- **Baseline JSON:** Updated post-completion to reflect corrected benchmark values (33 entries now includes `Rollback_ToVersion` which was previously failing).
+
+---
+
+## 4. Omitted or Deferred Items
+
+None. All items from the original plan were implemented.
+
+---
+
+## 5. Discrepancy Explanations
+
+| Item | Discrepancy | Explanation |
+|------|-------------|-------------|
+| **Version benchmarks (4 tests)** | Tests failed initially | Technical misunderstanding of Umbraco's versioning model. `Save()` updates the existing draft version; only `Publish()` creates a new version entry. The plan's comment "Create 100 versions by saving repeatedly" was incorrect. |
+| **HasChildren benchmark** | Test failed with double-count | The `MeasureAndRecord` warmup pattern executes the action twice (warmup + measurement). Variables captured in closures retain their values across both runs, causing the counter to accumulate. |
+| **Baseline JSON values** | 5 entries differ from original capture | Original baseline captured incorrect values because the version tests were measuring single-version queries instead of 100-version queries. Corrected values reflect actual versioning behavior. |
+| **Rollback_ToVersion in baseline** | Missing from original baseline | The test was failing during original baseline capture, so no JSON was emitted. Now included after fix. |
+
+---
+
+## 6. Key Achievements
+
+- **Comprehensive test coverage:** 15 integration tests covering notification ordering, sort operations, DeleteOfType, permissions, and transaction boundaries provide robust safety nets for refactoring.
+
+- **Benchmark infrastructure:** 33 benchmarks with JSON output enable automated regression detection across refactoring phases.
+
+- **Warmup pattern implementation:** Benchmarks correctly handle JIT warmup for accurate measurements, with `skipWarmup: true` for destructive operations.
+
+- **Tracking test for Phase 1:** The `ContentServiceBase_WhenCreated_UncommentTests` test will automatically detect when Phase 1 creates the `ContentServiceBase` class, prompting developers to activate the unit tests.
+
+- **Versioning behavior documentation:** The fix process documented an important Umbraco behavior: `Save()` updates drafts, `Publish()` creates versions. This knowledge is now captured in code comments (v1.3 remarks).
+
+- **Git tag for baseline:** The `phase-0-baseline` tag provides a clear rollback point and reference for future comparisons.
+
+---
+
+## 7. Final Assessment
+
+Phase 0 of the ContentService refactoring has been successfully completed. All planned test infrastructure is in place, with 15 integration tests validating behavioral contracts and 33 benchmarks establishing performance baselines. The post-completion fixes addressed implementation issues in 5 benchmark tests that stemmed from a misunderstanding of Umbraco's versioning model rather than issues with the ContentService itself.
+
+The baseline JSON now contains accurate measurements for all 33 benchmarks, providing a reliable foundation for regression detection in subsequent refactoring phases. The tracking test ensures that unit tests for `ContentServiceBase` will be activated automatically when Phase 1 begins. The infrastructure is ready for Phase 1 implementation.
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md
new file mode 100644
index 0000000000..544e5cbd2a
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase0-implementation.md
@@ -0,0 +1,2830 @@
+# ContentService Refactoring Phase 0 Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
+
+**Goal:** Create test and benchmark infrastructure to establish baseline metrics and safety nets before the ContentService refactoring begins.
+
+---
+
+## Revision History
+
+| Version | Date | Changes | Reviewer |
+|---------|------|---------|----------|
+| 1.0 | 2025-12-20 | Initial implementation plan | - |
+| 1.1 | 2025-12-20 | Applied critical review feedback (see below) | Critical Implementation Review |
+| 1.2 | 2025-12-20 | Applied critical review 2 feedback (warmup fix, data standardization) | Critical Implementation Review 2 |
+| 1.3 | 2025-12-20 | Applied critical review 3 feedback (see below) | Critical Implementation Review 3 |
+
+### v1.3 Changes (Critical Review 3 Feedback)
+
+**Must Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 1 | Variable shadowing causes compilation error | Task 3, Test 4, lines 509-511 | Removed `var` keyword from redeclared variables |
+| 2 | `ContentServiceBenchmarkBase.cs` not committed | Before Task 1 | Added Task 0 to commit the benchmark base class |
+
+**Should Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 3 | `MeasureAndRecord` missing warmup | `ContentServiceBenchmarkBase.cs` | Added warmup call to generic overload |
+| 4 | Missing tracking mechanism for ContentServiceBaseTests | Task 8 | Added tracking test that fails when `ContentServiceBase` is created |
+
+**Consider (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 5 | Permission test magic strings | Task 5, Tests 9-12 | Added inline permission code documentation |
+| 6 | No expected ranges in benchmarks | Task 7 | Added comment template for documenting ranges after baseline capture |
+| 7 | No JSON validation | Task 10 | Added optional jq validation step |
+
+---
+
+### v1.2 Changes (Critical Review 2 Feedback)
+
+**Must Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 1 | Warmup logic corrupts benchmark measurements | Task 7 - All non-destructive benchmarks | Restructured benchmarks to create separate warmup data, then fresh identical data for measurement |
+| 2 | Silent failure on missing baseline JSON | Task 10, Step 2 | Replaced `\|\| echo "[]"` with explicit error and exit on missing data |
+
+**Should Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 3 | `MeasureAndRecord` overload missing documentation | `ContentServiceBenchmarkBase.cs` | Added remarks about read-only usage intent |
+| 4 | Benchmark 31 index out of range risk | Task 7, Benchmark 31 | Added defensive assertion and use relative indexing (middle version) |
+| 5 | Sort tests assume specific initial sort order | Task 3, Tests 3-5 | Added explicit verification of initial state |
+| 6 | Inconsistent benchmark data sizes | Task 7 | Normalized to 10/100/1000 pattern (see table below) |
+| 7 | Permission accumulation behavior undocumented | Task 5, Test 10 | Added explicit behavior documentation |
+
+**Consider (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 8 | Test 13 unused variables | Task 6, Test 13 | Added clarifying comment about rolled-back transaction |
+| 9 | Missing Category for integration tests | Task 1 | Added `[Category("Refactoring")]` |
+| 10 | Benchmark 33 manual timing undocumented | Task 7, Benchmark 33 | Added comment explaining composite operation timing |
+
+**Benchmark Data Size Standardization (v1.2):**
+
+| Benchmark | Old Size | New Size | Change |
+|-----------|----------|----------|--------|
+| `Benchmark_Delete_WithDescendants` | 50 | 100 | +50 |
+| `Benchmark_Count_ByContentType` | 500 | 1000 | +500 |
+| `Benchmark_CountDescendants_LargeTree` | 500 | 1000 | +500 |
+| `Benchmark_Publish_BatchOf50` | 50 | 100 | Renamed to `Benchmark_Publish_BatchOf100` |
+| `Benchmark_PublishBranch_ShallowTree` | 20 | 100 | +80 |
+| `Benchmark_PerformScheduledPublish` | 50 | 100 | +50 |
+| `Benchmark_Move_WithDescendants` | 50 | 100 | +50 |
+| `Benchmark_MoveToRecycleBin_LargeTree` | 100 | 1000 | +900 |
+| `Benchmark_Copy_Recursive_50Items` | 50 | 100 | Renamed to `Benchmark_Copy_Recursive_100Items` |
+| `Benchmark_GetVersions_ItemWith50Versions` | 50 | 100 | Renamed to `Benchmark_GetVersions_ItemWith100Versions` |
+| `Benchmark_GetVersionsSlim_Paged` | 50 | 100 | +50 |
+| `Benchmark_DeleteVersions_ByDate` | 50 | 100 | +50 |
+
+---
+
+### v1.1 Changes (Critical Review Feedback)
+
+**Must Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 1 | Missing `[NonParallelizable]` attribute | Task 1 (test class) | Added `[NonParallelizable]` to prevent test flakiness from shared static state |
+| 2 | Incorrect using directive instruction | Task 6, Step 1 | Removed instruction; `ScopeProvider` available via base class |
+| 3 | Non-portable `grep -oP` command | Task 10, Step 2 | Replaced with POSIX-compliant `sed` command |
+| 4 | No benchmark warmup iterations | `ContentServiceBenchmarkBase.cs` | Added warmup to `MeasureAndRecord`; `skipWarmup: true` for destructive ops |
+| 5 | Missing null assertions on template | Task 4 (3 locations) | Added `Assert.That(template, Is.Not.Null, ...)` |
+
+**Should Fix (Applied):**
+
+| # | Issue | Location | Fix Applied |
+|---|-------|----------|-------------|
+| 7 | Benchmark class parallelization | Task 7 | Added `[NonParallelizable]` to benchmark class |
+
+**Destructive Benchmarks Updated with `skipWarmup: true`:**
+- `Benchmark_Delete_SingleItem`
+- `Benchmark_Delete_WithDescendants`
+- `Benchmark_EmptyRecycleBin_100Items`
+- `Benchmark_Rollback_ToVersion`
+- `Benchmark_DeleteVersions_ByDate`
+
+**Note:** Issue 6 (Design doc inconsistency) was verified - the implementation plan was already correct. MoveToRecycleBin does NOT fire unpublish notifications per `ContentService.cs` lines 2457-2461.
+
+---
+
+**Architecture:** Phase 0 delivers three test files: (1) ContentServiceRefactoringTests.cs with 15 integration tests covering notification ordering, sort operations, DeleteOfType, permissions, and transaction boundaries; (2) ContentServiceRefactoringBenchmarks.cs with 33 benchmarks; (3) ContentServiceBaseTests.cs with 7 unit tests for the shared infrastructure class.
+
+**Tech Stack:** NUnit, C#, .NET 10, Umbraco integration test infrastructure (UmbracoIntegrationTestWithContent, ContentServiceBenchmarkBase)
+
+---
+
+## Task 0: Commit ContentServiceBenchmarkBase.cs (Prerequisite)
+
+**Files:**
+- Commit: `tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs`
+
+**Context:** This file exists locally but is untracked in git. It must be committed before Task 1 or the benchmark tests will fail to compile for other developers.
+
+**Step 1: Verify the file exists and update MeasureAndRecord with warmup**
+
+Before committing, ensure `MeasureAndRecord` includes warmup (v1.3 fix). The method should look like:
+
+```csharp
+///
+/// Measures and records a benchmark, returning the result of the function.
+///
+///
+/// Performs a warmup call before measurement to trigger JIT compilation.
+/// Safe for read-only operations that can be repeated without side effects.
+///
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+{
+ // Warmup: triggers JIT compilation, warms caches
+ try { func(); } catch { /* ignore warmup errors */ }
+
+ var sw = Stopwatch.StartNew();
+ var result = func();
+ sw.Stop();
+ RecordBenchmark(name, sw.ElapsedMilliseconds, itemCount);
+ return result;
+}
+```
+
+**Step 2: Commit the benchmark infrastructure**
+
+Run:
+```bash
+git add tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs
+git commit -m "$(cat <<'EOF'
+test: add ContentServiceBenchmarkBase infrastructure class
+
+Adds base class for ContentService performance benchmarks with:
+- RecordBenchmark() for timing capture
+- MeasureAndRecord() with warmup support for non-destructive ops
+- MeasureAndRecord() with warmup for read-only ops returning values
+- JSON output wrapped in [BENCHMARK_JSON] markers for extraction
+- skipWarmup parameter for destructive operations
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 1: Create ContentServiceRefactoringTests.cs Skeleton
+
+**Files:**
+- Create: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**Step 1: Write the test file skeleton with notification handler**
+
+Create the test class with the notification handler setup required for tracking notification ordering.
+
+```csharp
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using NUnit.Framework;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Models.Entities;
+using Umbraco.Cms.Core.Notifications;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Tests.Common.Builders;
+using Umbraco.Cms.Tests.Common.Testing;
+using Umbraco.Cms.Tests.Integration.Testing;
+
+namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
+
+///
+/// Integration tests specifically for validating ContentService refactoring.
+/// These tests establish behavioral baselines that must pass throughout the refactoring phases.
+///
+[TestFixture]
+[NonParallelizable] // Required: static notification handler state is shared across tests
+[Category("Refactoring")] // v1.2: Added for easier test filtering during refactoring
+[UmbracoTest(
+ Database = UmbracoTestOptions.Database.NewSchemaPerTest,
+ PublishedRepositoryEvents = true,
+ WithApplication = true,
+ Logger = UmbracoTestOptions.Logger.Console)]
+internal sealed class ContentServiceRefactoringTests : UmbracoIntegrationTestWithContent
+{
+ private IContentTypeService ContentTypeService => GetRequiredService();
+ private IUserService UserService => GetRequiredService();
+
+ protected override void CustomTestSetup(IUmbracoBuilder builder) => builder
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler()
+ .AddNotificationHandler();
+
+ [SetUp]
+ public override void Setup()
+ {
+ base.Setup();
+ RefactoringTestNotificationHandler.Reset();
+ }
+
+ [TearDown]
+ public void Teardown()
+ {
+ RefactoringTestNotificationHandler.Reset();
+ }
+
+ #region Notification Ordering Tests
+
+ // Tests 1-2 will be added in Task 2
+
+ #endregion
+
+ #region Sort Operation Tests
+
+ // Tests 3-5 will be added in Task 3
+
+ #endregion
+
+ #region DeleteOfType Tests
+
+ // Tests 6-8 will be added in Task 4
+
+ #endregion
+
+ #region Permission Tests
+
+ // Tests 9-12 will be added in Task 5
+
+ #endregion
+
+ #region Transaction Boundary Tests
+
+ // Tests 13-15 will be added in Task 6
+
+ #endregion
+
+ ///
+ /// Notification handler that tracks the order of notifications for test verification.
+ ///
+ internal sealed class RefactoringTestNotificationHandler :
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler,
+ INotificationHandler
+ {
+ private static readonly List _notificationOrder = new();
+ private static readonly object _lock = new();
+
+ public static IReadOnlyList NotificationOrder
+ {
+ get
+ {
+ lock (_lock)
+ {
+ return _notificationOrder.ToList();
+ }
+ }
+ }
+
+ public static void Reset()
+ {
+ lock (_lock)
+ {
+ _notificationOrder.Clear();
+ }
+ }
+
+ private static void Record(string notificationType)
+ {
+ lock (_lock)
+ {
+ _notificationOrder.Add(notificationType);
+ }
+ }
+
+ public void Handle(ContentSavingNotification notification) => Record(nameof(ContentSavingNotification));
+ public void Handle(ContentSavedNotification notification) => Record(nameof(ContentSavedNotification));
+ public void Handle(ContentPublishingNotification notification) => Record(nameof(ContentPublishingNotification));
+ public void Handle(ContentPublishedNotification notification) => Record(nameof(ContentPublishedNotification));
+ public void Handle(ContentUnpublishingNotification notification) => Record(nameof(ContentUnpublishingNotification));
+ public void Handle(ContentUnpublishedNotification notification) => Record(nameof(ContentUnpublishedNotification));
+ public void Handle(ContentMovingNotification notification) => Record(nameof(ContentMovingNotification));
+ public void Handle(ContentMovedNotification notification) => Record(nameof(ContentMovedNotification));
+ public void Handle(ContentMovingToRecycleBinNotification notification) => Record(nameof(ContentMovingToRecycleBinNotification));
+ public void Handle(ContentMovedToRecycleBinNotification notification) => Record(nameof(ContentMovedToRecycleBinNotification));
+ public void Handle(ContentSortingNotification notification) => Record(nameof(ContentSortingNotification));
+ public void Handle(ContentSortedNotification notification) => Record(nameof(ContentSortedNotification));
+ public void Handle(ContentDeletingNotification notification) => Record(nameof(ContentDeletingNotification));
+ public void Handle(ContentDeletedNotification notification) => Record(nameof(ContentDeletedNotification));
+ }
+}
+```
+
+**Step 2: Run test to verify skeleton compiles**
+
+Run: `dotnet build tests/Umbraco.Tests.Integration`
+Expected: Build succeeds
+
+**Step 3: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add ContentServiceRefactoringTests skeleton for Phase 0
+
+Adds the test file skeleton with notification handler infrastructure
+for tracking notification ordering during ContentService refactoring.
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 2: Add Notification Ordering Tests (Tests 1-2)
+
+**Files:**
+- Modify: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**Step 1: Write Test 1 - MoveToRecycleBin_PublishedContent_FiresNotificationsInCorrectOrder**
+
+Add this test to the `#region Notification Ordering Tests` section:
+
+```csharp
+///
+/// Test 1: Verifies that MoveToRecycleBin for published content fires notifications in the correct order.
+/// Expected order: MovingToRecycleBin -> MovedToRecycleBin
+/// Note: As per design doc, MoveToRecycleBin does NOT unpublish first - content is "masked" not unpublished.
+///
+[Test]
+public void MoveToRecycleBin_PublishedContent_FiresNotificationsInCorrectOrder()
+{
+ // Arrange - Create and publish content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "TestContent", Textpage.Id);
+ ContentService.Save(content);
+ ContentService.Publish(content, new[] { "*" });
+
+ // Verify it's published
+ Assert.That(content.Published, Is.True, "Content should be published before test");
+
+ // Clear notification tracking
+ RefactoringTestNotificationHandler.Reset();
+
+ // Act
+ var result = ContentService.MoveToRecycleBin(content);
+
+ // Assert
+ Assert.That(result.Success, Is.True, "MoveToRecycleBin should succeed");
+
+ var notifications = RefactoringTestNotificationHandler.NotificationOrder;
+
+ // Verify notification sequence
+ Assert.That(notifications, Does.Contain(nameof(ContentMovingToRecycleBinNotification)),
+ "MovingToRecycleBin notification should fire");
+ Assert.That(notifications, Does.Contain(nameof(ContentMovedToRecycleBinNotification)),
+ "MovedToRecycleBin notification should fire");
+
+ // Verify order: Moving comes before Moved
+ var movingIndex = notifications.IndexOf(nameof(ContentMovingToRecycleBinNotification));
+ var movedIndex = notifications.IndexOf(nameof(ContentMovedToRecycleBinNotification));
+ Assert.That(movingIndex, Is.LessThan(movedIndex),
+ "MovingToRecycleBin should fire before MovedToRecycleBin");
+}
+```
+
+**Step 2: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.MoveToRecycleBin_PublishedContent_FiresNotificationsInCorrectOrder" -v n`
+Expected: PASS
+
+**Step 3: Write Test 2 - MoveToRecycleBin_UnpublishedContent_OnlyFiresMoveNotifications**
+
+Add this test to the same region:
+
+```csharp
+///
+/// Test 2: Verifies that MoveToRecycleBin for unpublished content only fires move notifications.
+/// No publish/unpublish notifications should be fired.
+///
+[Test]
+public void MoveToRecycleBin_UnpublishedContent_OnlyFiresMoveNotifications()
+{
+ // Arrange - Create content but don't publish
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "UnpublishedContent", Textpage.Id);
+ ContentService.Save(content);
+
+ // Verify it's not published
+ Assert.That(content.Published, Is.False, "Content should not be published before test");
+
+ // Clear notification tracking
+ RefactoringTestNotificationHandler.Reset();
+
+ // Act
+ var result = ContentService.MoveToRecycleBin(content);
+
+ // Assert
+ Assert.That(result.Success, Is.True, "MoveToRecycleBin should succeed");
+
+ var notifications = RefactoringTestNotificationHandler.NotificationOrder;
+
+ // Verify move notifications fire
+ Assert.That(notifications, Does.Contain(nameof(ContentMovingToRecycleBinNotification)),
+ "MovingToRecycleBin notification should fire");
+ Assert.That(notifications, Does.Contain(nameof(ContentMovedToRecycleBinNotification)),
+ "MovedToRecycleBin notification should fire");
+
+ // Verify no publish/unpublish notifications
+ Assert.That(notifications, Does.Not.Contain(nameof(ContentPublishingNotification)),
+ "Publishing notification should not fire for unpublished content");
+ Assert.That(notifications, Does.Not.Contain(nameof(ContentPublishedNotification)),
+ "Published notification should not fire for unpublished content");
+ Assert.That(notifications, Does.Not.Contain(nameof(ContentUnpublishingNotification)),
+ "Unpublishing notification should not fire for unpublished content");
+ Assert.That(notifications, Does.Not.Contain(nameof(ContentUnpublishedNotification)),
+ "Unpublished notification should not fire for unpublished content");
+}
+```
+
+**Step 4: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.MoveToRecycleBin_UnpublishedContent_OnlyFiresMoveNotifications" -v n`
+Expected: PASS
+
+**Step 5: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add notification ordering tests for MoveToRecycleBin
+
+Adds 2 integration tests validating notification order:
+- Test 1: Published content fires MovingToRecycleBin -> MovedToRecycleBin
+- Test 2: Unpublished content fires only move notifications, no publish notifications
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 3: Add Sort Operation Tests (Tests 3-5)
+
+**Files:**
+- Modify: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**Step 1: Write Test 3 - Sort_WithContentItems_ChangesSortOrder**
+
+Add this test to the `#region Sort Operation Tests` section:
+
+```csharp
+///
+/// Test 3: Verifies Sort(IEnumerable<IContent>) correctly reorders children.
+///
+[Test]
+public void Sort_WithContentItems_ChangesSortOrder()
+{
+ // Arrange - Use existing subpages from base class (Subpage, Subpage2, Subpage3)
+ // Get fresh copies to ensure we have current sort orders
+ var child1 = ContentService.GetById(Subpage.Id)!;
+ var child2 = ContentService.GetById(Subpage2.Id)!;
+ var child3 = ContentService.GetById(Subpage3.Id)!;
+
+ // v1.2: Verify initial sort order assumption
+ Assert.That(child1.SortOrder, Is.LessThan(child2.SortOrder), "Setup: child1 before child2");
+ Assert.That(child2.SortOrder, Is.LessThan(child3.SortOrder), "Setup: child2 before child3");
+
+ // Record original sort orders
+ var originalOrder1 = child1.SortOrder;
+ var originalOrder2 = child2.SortOrder;
+ var originalOrder3 = child3.SortOrder;
+
+ // Create reversed order list
+ var reorderedItems = new[] { child3, child2, child1 };
+
+ // Act
+ var result = ContentService.Sort(reorderedItems);
+
+ // Assert
+ Assert.That(result.Success, Is.True, "Sort should succeed");
+
+ // Re-fetch to verify persisted order
+ child1 = ContentService.GetById(Subpage.Id)!;
+ child2 = ContentService.GetById(Subpage2.Id)!;
+ child3 = ContentService.GetById(Subpage3.Id)!;
+
+ Assert.That(child3.SortOrder, Is.EqualTo(0), "Child3 should now be first (sort order 0)");
+ Assert.That(child2.SortOrder, Is.EqualTo(1), "Child2 should now be second (sort order 1)");
+ Assert.That(child1.SortOrder, Is.EqualTo(2), "Child1 should now be third (sort order 2)");
+}
+```
+
+**Step 2: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.Sort_WithContentItems_ChangesSortOrder" -v n`
+Expected: PASS
+
+**Step 3: Write Test 4 - Sort_WithIds_ChangesSortOrder**
+
+```csharp
+///
+/// Test 4: Verifies Sort(IEnumerable<int>) correctly reorders children by ID.
+///
+[Test]
+public void Sort_WithIds_ChangesSortOrder()
+{
+ // Arrange - Use existing subpages from base class
+ var child1 = ContentService.GetById(Subpage.Id)!;
+ var child2 = ContentService.GetById(Subpage2.Id)!;
+ var child3 = ContentService.GetById(Subpage3.Id)!;
+
+ // v1.2: Verify initial sort order assumption
+ Assert.That(child1.SortOrder, Is.LessThan(child2.SortOrder), "Setup: child1 before child2");
+ Assert.That(child2.SortOrder, Is.LessThan(child3.SortOrder), "Setup: child2 before child3");
+
+ var child1Id = Subpage.Id;
+ var child2Id = Subpage2.Id;
+ var child3Id = Subpage3.Id;
+
+ // Create reversed order list by ID
+ var reorderedIds = new[] { child3Id, child2Id, child1Id };
+
+ // Act
+ var result = ContentService.Sort(reorderedIds);
+
+ // Assert
+ Assert.That(result.Success, Is.True, "Sort should succeed");
+
+ // Re-fetch to verify persisted order (v1.3: removed var to avoid shadowing)
+ child1 = ContentService.GetById(child1Id)!;
+ child2 = ContentService.GetById(child2Id)!;
+ child3 = ContentService.GetById(child3Id)!;
+
+ Assert.That(child3.SortOrder, Is.EqualTo(0), "Child3 should now be first (sort order 0)");
+ Assert.That(child2.SortOrder, Is.EqualTo(1), "Child2 should now be second (sort order 1)");
+ Assert.That(child1.SortOrder, Is.EqualTo(2), "Child1 should now be third (sort order 2)");
+}
+```
+
+**Step 4: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.Sort_WithIds_ChangesSortOrder" -v n`
+Expected: PASS
+
+**Step 5: Write Test 5 - Sort_FiresSortingAndSortedNotifications**
+
+```csharp
+///
+/// Test 5: Verifies Sort fires Sorting and Sorted notifications in correct sequence.
+///
+[Test]
+public void Sort_FiresSortingAndSortedNotifications()
+{
+ // Arrange - Use existing subpages from base class
+ var child1 = ContentService.GetById(Subpage.Id)!;
+ var child2 = ContentService.GetById(Subpage2.Id)!;
+ var child3 = ContentService.GetById(Subpage3.Id)!;
+
+ // v1.2: Verify initial sort order assumption
+ Assert.That(child1.SortOrder, Is.LessThan(child2.SortOrder), "Setup: child1 before child2");
+ Assert.That(child2.SortOrder, Is.LessThan(child3.SortOrder), "Setup: child2 before child3");
+
+ var reorderedItems = new[] { child3, child2, child1 };
+
+ // Clear notification tracking
+ RefactoringTestNotificationHandler.Reset();
+
+ // Act
+ var result = ContentService.Sort(reorderedItems);
+
+ // Assert
+ Assert.That(result.Success, Is.True, "Sort should succeed");
+
+ var notifications = RefactoringTestNotificationHandler.NotificationOrder;
+
+ // Verify both sorting notifications fire
+ Assert.That(notifications, Does.Contain(nameof(ContentSortingNotification)),
+ "Sorting notification should fire");
+ Assert.That(notifications, Does.Contain(nameof(ContentSortedNotification)),
+ "Sorted notification should fire");
+
+ // Also verify Saving/Saved fire (Sort saves content)
+ Assert.That(notifications, Does.Contain(nameof(ContentSavingNotification)),
+ "Saving notification should fire during sort");
+ Assert.That(notifications, Does.Contain(nameof(ContentSavedNotification)),
+ "Saved notification should fire during sort");
+
+ // Verify order: Sorting -> Saving -> Saved -> Sorted
+ var sortingIndex = notifications.IndexOf(nameof(ContentSortingNotification));
+ var sortedIndex = notifications.IndexOf(nameof(ContentSortedNotification));
+
+ Assert.That(sortingIndex, Is.LessThan(sortedIndex),
+ "Sorting should fire before Sorted");
+}
+```
+
+**Step 6: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.Sort_FiresSortingAndSortedNotifications" -v n`
+Expected: PASS
+
+**Step 7: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add sort operation tests for ContentService refactoring
+
+Adds 3 integration tests for Sort operations:
+- Test 3: Sort(IEnumerable) reorders children correctly
+- Test 4: Sort(IEnumerable) reorders children by ID correctly
+- Test 5: Sort fires Sorting and Sorted notifications in sequence
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 4: Add DeleteOfType Tests (Tests 6-8)
+
+**Files:**
+- Modify: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**Step 1: Write Test 6 - DeleteOfType_MovesDescendantsToRecycleBinFirst**
+
+Add this test to the `#region DeleteOfType Tests` section:
+
+```csharp
+///
+/// Test 6: Verifies DeleteOfType with hierarchical content deletes everything correctly.
+///
+[Test]
+public void DeleteOfType_MovesDescendantsToRecycleBinFirst()
+{
+ // Arrange - Create a second content type for descendants
+ var template = FileService.GetTemplate("defaultTemplate");
+ Assert.That(template, Is.Not.Null, "Default template must exist for test setup");
+ var childContentType = ContentTypeBuilder.CreateSimpleContentType(
+ "childType", "Child Type", defaultTemplateId: template!.Id);
+ ContentTypeService.Save(childContentType);
+
+ // Create parent of target type
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "ParentToDelete", -1);
+ ContentService.Save(parent);
+
+ // Create child of different type (should be moved to bin, not deleted)
+ var childOfDifferentType = ContentBuilder.CreateSimpleContent(childContentType, "ChildDifferentType", parent.Id);
+ ContentService.Save(childOfDifferentType);
+
+ // Create child of same type (should be deleted)
+ var childOfSameType = ContentBuilder.CreateSimpleContent(ContentType, "ChildSameType", parent.Id);
+ ContentService.Save(childOfSameType);
+
+ var parentId = parent.Id;
+ var childDiffId = childOfDifferentType.Id;
+ var childSameId = childOfSameType.Id;
+
+ // Act
+ ContentService.DeleteOfType(ContentType.Id);
+
+ // Assert
+ // Parent should be deleted (it's the target type)
+ var deletedParent = ContentService.GetById(parentId);
+ Assert.That(deletedParent, Is.Null, "Parent of target type should be deleted");
+
+ // Child of same type should be deleted
+ var deletedChildSame = ContentService.GetById(childSameId);
+ Assert.That(deletedChildSame, Is.Null, "Child of same type should be deleted");
+
+ // Child of different type should be in recycle bin
+ var trashedChild = ContentService.GetById(childDiffId);
+ Assert.That(trashedChild, Is.Not.Null, "Child of different type should still exist");
+ Assert.That(trashedChild!.Trashed, Is.True, "Child of different type should be in recycle bin");
+}
+```
+
+**Step 2: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.DeleteOfType_MovesDescendantsToRecycleBinFirst" -v n`
+Expected: PASS
+
+**Step 3: Write Test 7 - DeleteOfType_WithMixedTypes_OnlyDeletesSpecifiedType**
+
+```csharp
+///
+/// Test 7: Verifies DeleteOfType only deletes content of the specified type.
+///
+[Test]
+public void DeleteOfType_WithMixedTypes_OnlyDeletesSpecifiedType()
+{
+ // Arrange - Create a second content type
+ var template = FileService.GetTemplate("defaultTemplate");
+ Assert.That(template, Is.Not.Null, "Default template must exist for test setup");
+ var otherContentType = ContentTypeBuilder.CreateSimpleContentType(
+ "otherType", "Other Type", defaultTemplateId: template!.Id);
+ ContentTypeService.Save(otherContentType);
+
+ // Create content of target type
+ var targetContent1 = ContentBuilder.CreateSimpleContent(ContentType, "Target1", -1);
+ var targetContent2 = ContentBuilder.CreateSimpleContent(ContentType, "Target2", -1);
+ ContentService.Save(targetContent1);
+ ContentService.Save(targetContent2);
+
+ // Create content of other type (should survive)
+ var otherContent = ContentBuilder.CreateSimpleContent(otherContentType, "Other", -1);
+ ContentService.Save(otherContent);
+
+ var target1Id = targetContent1.Id;
+ var target2Id = targetContent2.Id;
+ var otherId = otherContent.Id;
+
+ // Act
+ ContentService.DeleteOfType(ContentType.Id);
+
+ // Assert
+ Assert.That(ContentService.GetById(target1Id), Is.Null, "Target1 should be deleted");
+ Assert.That(ContentService.GetById(target2Id), Is.Null, "Target2 should be deleted");
+ Assert.That(ContentService.GetById(otherId), Is.Not.Null, "Other type content should survive");
+ Assert.That(ContentService.GetById(otherId)!.Trashed, Is.False, "Other type content should not be trashed");
+}
+```
+
+**Step 4: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.DeleteOfType_WithMixedTypes_OnlyDeletesSpecifiedType" -v n`
+Expected: PASS
+
+**Step 5: Write Test 8 - DeleteOfTypes_DeletesMultipleTypesAtOnce**
+
+```csharp
+///
+/// Test 8: Verifies DeleteOfTypes deletes multiple content types in a single operation.
+///
+[Test]
+public void DeleteOfTypes_DeletesMultipleTypesAtOnce()
+{
+ // Arrange - Create additional content types
+ var template = FileService.GetTemplate("defaultTemplate");
+ Assert.That(template, Is.Not.Null, "Default template must exist for test setup");
+
+ var type1 = ContentTypeBuilder.CreateSimpleContentType(
+ "deleteType1", "Delete Type 1", defaultTemplateId: template!.Id);
+ var type2 = ContentTypeBuilder.CreateSimpleContentType(
+ "deleteType2", "Delete Type 2", defaultTemplateId: template.Id);
+ var survivorType = ContentTypeBuilder.CreateSimpleContentType(
+ "survivorType", "Survivor Type", defaultTemplateId: template.Id);
+
+ ContentTypeService.Save(type1);
+ ContentTypeService.Save(type2);
+ ContentTypeService.Save(survivorType);
+
+ // Create content of each type
+ var content1 = ContentBuilder.CreateSimpleContent(type1, "Content1", -1);
+ var content2 = ContentBuilder.CreateSimpleContent(type2, "Content2", -1);
+ var survivor = ContentBuilder.CreateSimpleContent(survivorType, "Survivor", -1);
+
+ ContentService.Save(content1);
+ ContentService.Save(content2);
+ ContentService.Save(survivor);
+
+ var content1Id = content1.Id;
+ var content2Id = content2.Id;
+ var survivorId = survivor.Id;
+
+ // Act - Delete multiple types
+ ContentService.DeleteOfTypes(new[] { type1.Id, type2.Id });
+
+ // Assert
+ Assert.That(ContentService.GetById(content1Id), Is.Null, "Content of type1 should be deleted");
+ Assert.That(ContentService.GetById(content2Id), Is.Null, "Content of type2 should be deleted");
+ Assert.That(ContentService.GetById(survivorId), Is.Not.Null, "Content of survivor type should exist");
+}
+```
+
+**Step 6: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.DeleteOfTypes_DeletesMultipleTypesAtOnce" -v n`
+Expected: PASS
+
+**Step 7: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add DeleteOfType tests for ContentService refactoring
+
+Adds 3 integration tests for DeleteOfType operations:
+- Test 6: DeleteOfType handles descendants correctly (moves different types to bin)
+- Test 7: DeleteOfType only deletes specified type, preserves others
+- Test 8: DeleteOfTypes deletes multiple content types at once
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 5: Add Permission Tests (Tests 9-12)
+
+**Files:**
+- Modify: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**v1.3: Permission Code Reference**
+
+The following permission codes are used in these tests (see `Umbraco.Cms.Core.Actions` for full list):
+
+| Code | Permission | Action Class |
+|------|------------|--------------|
+| `F` | Browse Node | `ActionBrowse` |
+| `U` | Update | `ActionUpdate` |
+| `P` | Publish | `ActionPublish` |
+| `D` | Delete | `ActionDelete` |
+| `R` | Rights | `ActionRights` |
+
+**Step 1: Write Test 9 - SetPermission_AssignsPermissionToUserGroup**
+
+Add this test to the `#region Permission Tests` section:
+
+```csharp
+///
+/// Test 9: Verifies SetPermission assigns a permission and GetPermissions retrieves it.
+///
+[Test]
+public void SetPermission_AssignsPermissionToUserGroup()
+{
+ // Arrange
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "PermissionTest", -1);
+ ContentService.Save(content);
+
+ // Get admin user group ID (should always exist)
+ var adminGroup = UserService.GetUserGroupByAlias(Constants.Security.AdminGroupAlias);
+ Assert.That(adminGroup, Is.Not.Null, "Admin group should exist");
+
+ // Act - Assign browse permission ('F' is typically the Browse Node permission)
+ ContentService.SetPermission(content, "F", new[] { adminGroup!.Id });
+
+ // Assert
+ var permissions = ContentService.GetPermissions(content);
+ Assert.That(permissions, Is.Not.Null, "Permissions should be returned");
+
+ var adminPermissions = permissions.FirstOrDefault(p => p.UserGroupId == adminGroup.Id);
+ Assert.That(adminPermissions, Is.Not.Null, "Should have permissions for admin group");
+ Assert.That(adminPermissions!.AssignedPermissions, Does.Contain("F"),
+ "Admin group should have Browse permission");
+}
+```
+
+**Step 2: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.SetPermission_AssignsPermissionToUserGroup" -v n`
+Expected: PASS
+
+**Step 3: Write Test 10 - SetPermission_MultiplePermissionsForSameGroup**
+
+```csharp
+///
+/// Test 10: Verifies multiple SetPermission calls accumulate permissions for a user group.
+///
+///
+/// v1.2: Expected behavior documentation -
+/// SetPermission assigns permissions per-permission-type, not per-entity.
+/// Calling SetPermission("F", ...) then SetPermission("U", ...) results in both F and U
+/// permissions being assigned. Each call only replaces permissions of the same type.
+///
+[Test]
+public void SetPermission_MultiplePermissionsForSameGroup()
+{
+ // Arrange
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "MultiPermissionTest", -1);
+ ContentService.Save(content);
+
+ var adminGroup = UserService.GetUserGroupByAlias(Constants.Security.AdminGroupAlias)!;
+
+ // Act - Assign multiple permissions
+ ContentService.SetPermission(content, "F", new[] { adminGroup.Id }); // Browse
+ ContentService.SetPermission(content, "U", new[] { adminGroup.Id }); // Update
+
+ // Assert
+ var permissions = ContentService.GetPermissions(content);
+ var adminPermissions = permissions.FirstOrDefault(p => p.UserGroupId == adminGroup.Id);
+
+ Assert.That(adminPermissions, Is.Not.Null, "Should have permissions for admin group");
+ Assert.That(adminPermissions!.AssignedPermissions, Does.Contain("F"), "Should have Browse permission");
+ Assert.That(adminPermissions.AssignedPermissions, Does.Contain("U"), "Should have Update permission");
+}
+```
+
+**Step 4: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.SetPermission_MultiplePermissionsForSameGroup" -v n`
+Expected: PASS
+
+**Step 5: Write Test 11 - SetPermissions_AssignsPermissionSet**
+
+```csharp
+///
+/// Test 11: Verifies SetPermissions assigns a complete permission set.
+///
+[Test]
+public void SetPermissions_AssignsPermissionSet()
+{
+ // Arrange
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "PermissionSetTest", -1);
+ ContentService.Save(content);
+
+ var adminGroup = UserService.GetUserGroupByAlias(Constants.Security.AdminGroupAlias)!;
+
+ // Create permission set
+ var permissionSet = new EntityPermissionSet(
+ content.Id,
+ new EntityPermissionCollection(new[]
+ {
+ new EntityPermission(adminGroup.Id, content.Id, new[] { "F", "U", "P" }) // Browse, Update, Publish
+ }));
+
+ // Act
+ ContentService.SetPermissions(permissionSet);
+
+ // Assert
+ var permissions = ContentService.GetPermissions(content);
+ var adminPermissions = permissions.FirstOrDefault(p => p.UserGroupId == adminGroup.Id);
+
+ Assert.That(adminPermissions, Is.Not.Null, "Should have permissions for admin group");
+ Assert.That(adminPermissions!.AssignedPermissions, Does.Contain("F"), "Should have Browse permission");
+ Assert.That(adminPermissions.AssignedPermissions, Does.Contain("U"), "Should have Update permission");
+ Assert.That(adminPermissions.AssignedPermissions, Does.Contain("P"), "Should have Publish permission");
+}
+```
+
+**Step 6: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.SetPermissions_AssignsPermissionSet" -v n`
+Expected: PASS
+
+**Step 7: Write Test 12 - SetPermission_AssignsToMultipleUserGroups**
+
+```csharp
+///
+/// Test 12: Verifies SetPermission can assign to multiple user groups simultaneously.
+///
+[Test]
+public void SetPermission_AssignsToMultipleUserGroups()
+{
+ // Arrange
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "MultiGroupTest", -1);
+ ContentService.Save(content);
+
+ var adminGroup = UserService.GetUserGroupByAlias(Constants.Security.AdminGroupAlias)!;
+ var editorGroup = UserService.GetUserGroupByAlias(Constants.Security.EditorGroupAlias)!;
+
+ // Act - Assign permission to multiple groups at once
+ ContentService.SetPermission(content, "F", new[] { adminGroup.Id, editorGroup.Id });
+
+ // Assert
+ var permissions = ContentService.GetPermissions(content);
+
+ var adminPermissions = permissions.FirstOrDefault(p => p.UserGroupId == adminGroup.Id);
+ var editorPermissions = permissions.FirstOrDefault(p => p.UserGroupId == editorGroup.Id);
+
+ Assert.That(adminPermissions, Is.Not.Null, "Should have permissions for admin group");
+ Assert.That(adminPermissions!.AssignedPermissions, Does.Contain("F"), "Admin should have Browse permission");
+
+ Assert.That(editorPermissions, Is.Not.Null, "Should have permissions for editor group");
+ Assert.That(editorPermissions!.AssignedPermissions, Does.Contain("F"), "Editor should have Browse permission");
+}
+```
+
+**Step 8: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.SetPermission_AssignsToMultipleUserGroups" -v n`
+Expected: PASS
+
+**Step 9: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add permission tests for ContentService refactoring
+
+Adds 4 integration tests for permission operations:
+- Test 9: SetPermission assigns permission and GetPermissions retrieves it
+- Test 10: Multiple SetPermission calls accumulate permissions
+- Test 11: SetPermissions assigns complete permission set
+- Test 12: SetPermission assigns to multiple user groups at once
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 6: Add Transaction Boundary Tests (Tests 13-15)
+
+**Files:**
+- Modify: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs`
+
+**Step 1: Write Test 13 - AmbientScope_NestedOperationsShareTransaction**
+
+Add these tests to the `#region Transaction Boundary Tests` section. Note: `ScopeProvider` is already accessible via the `UmbracoIntegrationTestWithContent` base class, no additional using directive needed.
+
+Add the test:
+
+```csharp
+///
+/// Test 13: Verifies that multiple operations within an uncompleted scope all roll back together.
+///
+[Test]
+public void AmbientScope_NestedOperationsShareTransaction()
+{
+ // Arrange
+ var content1 = ContentBuilder.CreateSimpleContent(ContentType, "RollbackTest1", -1);
+ var content2 = ContentBuilder.CreateSimpleContent(ContentType, "RollbackTest2", -1);
+
+ // Act - Create scope, save content, but don't complete the scope
+ using (var scope = ScopeProvider.CreateScope())
+ {
+ ContentService.Save(content1);
+ ContentService.Save(content2);
+
+ // Verify content has IDs (was saved within transaction)
+ Assert.That(content1.Id, Is.GreaterThan(0), "Content1 should have an ID");
+ Assert.That(content2.Id, Is.GreaterThan(0), "Content2 should have an ID");
+
+ // v1.2: Note - IDs are captured for debugging but cannot be used after rollback
+ // since they were assigned within the rolled-back transaction
+ var id1 = content1.Id;
+ var id2 = content2.Id;
+
+ // DON'T call scope.Complete() - should roll back
+ }
+
+ // Assert - Content should not exist after rollback
+ // We can't use the IDs because they were assigned in the rolled-back transaction
+ // Instead, search by name
+ var foundContent = ContentService.GetRootContent()
+ .Where(c => c.Name == "RollbackTest1" || c.Name == "RollbackTest2")
+ .ToList();
+
+ Assert.That(foundContent, Is.Empty, "Content should not exist after transaction rollback");
+}
+```
+
+**Step 2: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.AmbientScope_NestedOperationsShareTransaction" -v n`
+Expected: PASS
+
+**Step 3: Write Test 14 - AmbientScope_CompletedScopeCommitsAllOperations**
+
+```csharp
+///
+/// Test 14: Verifies that multiple operations within a completed scope all commit together.
+///
+[Test]
+public void AmbientScope_CompletedScopeCommitsAllOperations()
+{
+ // Arrange
+ var content1 = ContentBuilder.CreateSimpleContent(ContentType, "CommitTest1", -1);
+ var content2 = ContentBuilder.CreateSimpleContent(ContentType, "CommitTest2", -1);
+ int id1, id2;
+
+ // Act - Create scope, save content, and complete the scope
+ using (var scope = ScopeProvider.CreateScope())
+ {
+ ContentService.Save(content1);
+ ContentService.Save(content2);
+
+ id1 = content1.Id;
+ id2 = content2.Id;
+
+ scope.Complete(); // Commit transaction
+ }
+
+ // Assert - Content should exist after commit
+ var retrieved1 = ContentService.GetById(id1);
+ var retrieved2 = ContentService.GetById(id2);
+
+ Assert.That(retrieved1, Is.Not.Null, "Content1 should exist after commit");
+ Assert.That(retrieved2, Is.Not.Null, "Content2 should exist after commit");
+ Assert.That(retrieved1!.Name, Is.EqualTo("CommitTest1"));
+ Assert.That(retrieved2!.Name, Is.EqualTo("CommitTest2"));
+}
+```
+
+**Step 4: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.AmbientScope_CompletedScopeCommitsAllOperations" -v n`
+Expected: PASS
+
+**Step 5: Write Test 15 - AmbientScope_MoveToRecycleBinRollsBackCompletely**
+
+```csharp
+///
+/// Test 15: Verifies MoveToRecycleBin within an uncompleted scope rolls back completely.
+///
+[Test]
+public void AmbientScope_MoveToRecycleBinRollsBackCompletely()
+{
+ // Arrange - Create and save content OUTSIDE the test scope so it persists
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "MoveRollbackTest", -1);
+ ContentService.Save(content);
+ var contentId = content.Id;
+
+ // Verify content exists and is not trashed
+ var beforeMove = ContentService.GetById(contentId);
+ Assert.That(beforeMove, Is.Not.Null, "Content should exist before test");
+ Assert.That(beforeMove!.Trashed, Is.False, "Content should not be trashed before test");
+
+ // Act - Move to recycle bin within an uncompleted scope
+ using (var scope = ScopeProvider.CreateScope())
+ {
+ ContentService.MoveToRecycleBin(content);
+
+ // Verify it's trashed within the transaction
+ var duringMove = ContentService.GetById(contentId);
+ Assert.That(duringMove!.Trashed, Is.True, "Content should be trashed within transaction");
+
+ // DON'T call scope.Complete() - should roll back
+ }
+
+ // Assert - Content should be back to original state after rollback
+ var afterRollback = ContentService.GetById(contentId);
+ Assert.That(afterRollback, Is.Not.Null, "Content should still exist after rollback");
+ Assert.That(afterRollback!.Trashed, Is.False, "Content should not be trashed after rollback");
+ Assert.That(afterRollback.ParentId, Is.EqualTo(-1), "Content should be at root level after rollback");
+}
+```
+
+**Step 6: Run test to verify it passes**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests.AmbientScope_MoveToRecycleBinRollsBackCompletely" -v n`
+Expected: PASS
+
+**Step 7: Run all 15 tests together to verify**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests" -v n`
+Expected: All 15 tests PASS
+
+**Step 8: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+git commit -m "$(cat <<'EOF'
+test: add transaction boundary tests for ContentService refactoring
+
+Adds 3 integration tests for transaction boundaries:
+- Test 13: Nested operations in uncompleted scope roll back together
+- Test 14: Completed scope commits all operations together
+- Test 15: MoveToRecycleBin rolls back completely when scope not completed
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 7: Create ContentServiceRefactoringBenchmarks.cs
+
+**Files:**
+- Create: `tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringBenchmarks.cs`
+
+**Step 1: Write the benchmark file**
+
+```csharp
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using System.Diagnostics;
+using NUnit.Framework;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Services;
+using Umbraco.Cms.Tests.Common.Attributes;
+using Umbraco.Cms.Tests.Common.Builders;
+using Umbraco.Cms.Tests.Common.Testing;
+using Umbraco.Cms.Tests.Integration.Testing;
+
+namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
+
+///
+/// Performance benchmarks for ContentService operations.
+/// Used to establish baseline metrics and detect regressions during refactoring.
+///
+///
+/// Run with: dotnet test --filter "Category=Benchmark&FullyQualifiedName~ContentServiceRefactoringBenchmarks"
+/// Results are output in JSON format for baseline comparison.
+///
+/// v1.3 EXPECTED RANGES:
+/// After capturing the Phase 0 baseline, document expected ranges in docs/plans/baseline-phase0.json.
+/// Future phases may add threshold-based assertions. For now, benchmarks capture timing only.
+/// Example expected range comment (to be added after baseline capture):
+/// // Baseline: ~50ms, Acceptable range: <100ms
+///
+/// v1.2 WARMUP PATTERN:
+/// - For non-destructive benchmarks that MUTATE data (Save, Publish, etc.):
+/// Create throwaway data for warmup (triggers JIT, warms caches), then
+/// create fresh identical data for the measured run.
+/// - For read-only benchmarks (GetById, GetByIds, etc.):
+/// Use MeasureAndRecord with warmup enabled (default).
+/// - For destructive benchmarks (Delete, EmptyRecycleBin, etc.):
+/// Use skipWarmup: true since operation cannot be repeated.
+///
+[TestFixture]
+[NonParallelizable] // Required: benchmarks need isolated database access for accurate measurements
+[UmbracoTest(
+ Database = UmbracoTestOptions.Database.NewSchemaPerTest,
+ PublishedRepositoryEvents = true,
+ WithApplication = true,
+ Logger = UmbracoTestOptions.Logger.Console)]
+[Category("Benchmark")]
+[Category("LongRunning")]
+internal sealed class ContentServiceRefactoringBenchmarks : ContentServiceBenchmarkBase
+{
+ private IContentTypeService ContentTypeService => GetRequiredService();
+
+ #region CRUD Operation Benchmarks (7 tests)
+
+ ///
+ /// Benchmark 1: Single content save latency.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Save_SingleItem()
+ {
+ // v1.2: Warmup with throwaway content (triggers JIT, warms caches)
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_SingleItem", -1);
+ ContentService.Save(warmupContent);
+
+ // Measured run with fresh, identical setup
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "BenchmarkSingle", -1);
+ var sw = Stopwatch.StartNew();
+ ContentService.Save(content);
+ sw.Stop();
+ RecordBenchmark("Save_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Id, Is.GreaterThan(0));
+ }
+
+ ///
+ /// Benchmark 2: Batch save of 100 items.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Save_BatchOf100()
+ {
+ const int itemCount = 100;
+
+ // v1.2: Warmup with throwaway batch
+ var warmupItems = new List();
+ for (var i = 0; i < itemCount; i++)
+ {
+ warmupItems.Add(ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_Batch100_{i}", -1));
+ }
+ ContentService.Save(warmupItems);
+
+ // Measured run with fresh batch
+ var items = new List();
+ for (var i = 0; i < itemCount; i++)
+ {
+ items.Add(ContentBuilder.CreateSimpleContent(ContentType, $"Batch100_{i}", -1));
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Save(items);
+ sw.Stop();
+ RecordBenchmark("Save_BatchOf100", sw.ElapsedMilliseconds, itemCount);
+
+ Assert.That(items.All(c => c.Id > 0), Is.True);
+ }
+
+ ///
+ /// Benchmark 3: Batch save of 1000 items (scalability test).
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Save_BatchOf1000()
+ {
+ const int itemCount = 1000;
+
+ // v1.2: Warmup with smaller batch (100 items sufficient for JIT warmup)
+ var warmupItems = new List();
+ for (var i = 0; i < 100; i++)
+ {
+ warmupItems.Add(ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_Batch1000_{i}", -1));
+ }
+ ContentService.Save(warmupItems);
+
+ // Measured run with fresh batch
+ var items = new List();
+ for (var i = 0; i < itemCount; i++)
+ {
+ items.Add(ContentBuilder.CreateSimpleContent(ContentType, $"Batch1000_{i}", -1));
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Save(items);
+ sw.Stop();
+ RecordBenchmark("Save_BatchOf1000", sw.ElapsedMilliseconds, itemCount);
+
+ Assert.That(items.All(c => c.Id > 0), Is.True);
+ }
+
+ ///
+ /// Benchmark 4: Single item retrieval by ID.
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetById_Single()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "GetByIdTest", -1);
+ ContentService.Save(content);
+ var id = content.Id;
+
+ IContent? result = null;
+ MeasureAndRecord("GetById_Single", 1, () =>
+ {
+ result = ContentService.GetById(id);
+ });
+
+ Assert.That(result, Is.Not.Null);
+ }
+
+ ///
+ /// Benchmark 5: Batch retrieval of 100 items (N+1 detection).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetByIds_BatchOf100()
+ {
+ const int itemCount = 100;
+ var items = new List();
+
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"GetByIds_{i}", -1);
+ ContentService.Save(content);
+ items.Add(content);
+ }
+
+ var ids = items.Select(c => c.Id).ToList();
+
+ IEnumerable? results = null;
+ MeasureAndRecord("GetByIds_BatchOf100", itemCount, () =>
+ {
+ results = ContentService.GetByIds(ids);
+ });
+
+ Assert.That(results!.Count(), Is.EqualTo(itemCount));
+ }
+
+ ///
+ /// Benchmark 6: Single item deletion.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Delete_SingleItem()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "DeleteTest", -1);
+ ContentService.Save(content);
+
+ MeasureAndRecord("Delete_SingleItem", 1, () =>
+ {
+ ContentService.Delete(content);
+ }, skipWarmup: true); // Destructive operation - cannot repeat
+
+ Assert.That(ContentService.GetById(content.Id), Is.Null);
+ }
+
+ ///
+ /// Benchmark 7: Delete item with 100 descendants (cascade performance).
+ ///
+ /// v1.2: Standardized from 50 to 100 descendants.
+ [Test]
+ [LongRunning]
+ public void Benchmark_Delete_WithDescendants()
+ {
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "DeleteParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"DeleteChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ MeasureAndRecord("Delete_WithDescendants", childCount + 1, () =>
+ {
+ ContentService.Delete(parent);
+ }, skipWarmup: true); // Destructive operation - cannot repeat
+
+ Assert.That(ContentService.GetById(parent.Id), Is.Null);
+ }
+
+ #endregion
+
+ #region Query Operation Benchmarks (6 tests)
+
+ ///
+ /// Benchmark 8: Paged children query (100 items).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetPagedChildren_100Items()
+ {
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "PagedParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100;
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"PagedChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ IEnumerable? results = null;
+ long totalRecords = 0;
+
+ MeasureAndRecord("GetPagedChildren_100Items", childCount, () =>
+ {
+ results = ContentService.GetPagedChildren(parent.Id, 0, 100, out totalRecords);
+ });
+
+ Assert.That(totalRecords, Is.EqualTo(childCount));
+ }
+
+ ///
+ /// Benchmark 9: Paged descendants query (deep tree, 300 total).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetPagedDescendants_DeepTree()
+ {
+ var root = ContentBuilder.CreateSimpleContent(ContentType, "DeepRoot", -1);
+ ContentService.Save(root);
+
+ // Create 3 levels, 100 items each
+ const int itemsPerLevel = 100;
+ var currentParent = root;
+
+ for (var level = 0; level < 3; level++)
+ {
+ var firstChild = ContentBuilder.CreateSimpleContent(ContentType, $"Level{level}_0", currentParent.Id);
+ ContentService.Save(firstChild);
+
+ for (var i = 1; i < itemsPerLevel; i++)
+ {
+ var sibling = ContentBuilder.CreateSimpleContent(ContentType, $"Level{level}_{i}", currentParent.Id);
+ ContentService.Save(sibling);
+ }
+
+ currentParent = firstChild;
+ }
+
+ IEnumerable? results = null;
+ long totalRecords = 0;
+
+ MeasureAndRecord("GetPagedDescendants_DeepTree", 300, () =>
+ {
+ results = ContentService.GetPagedDescendants(root.Id, 0, 1000, out totalRecords);
+ });
+
+ Assert.That(totalRecords, Is.EqualTo(300));
+ }
+
+ ///
+ /// Benchmark 10: Get ancestors of deep item (N+1 prone).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetAncestors_DeepHierarchy()
+ {
+ const int depth = 10;
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "AncestorRoot", -1);
+ ContentService.Save(parent);
+
+ var current = parent;
+ for (var i = 0; i < depth - 1; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"Ancestor_{i}", current.Id);
+ ContentService.Save(child);
+ current = child;
+ }
+
+ var deepestId = current.Id;
+
+ IEnumerable? results = null;
+ MeasureAndRecord("GetAncestors_DeepHierarchy", depth, () =>
+ {
+ results = ContentService.GetAncestors(deepestId);
+ });
+
+ Assert.That(results!.Count(), Is.EqualTo(depth - 1)); // Excludes self
+ }
+
+ ///
+ /// Benchmark 11: Count by content type (1000 items).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe. Standardized from 500 to 1000.
+ [Test]
+ [LongRunning]
+ public void Benchmark_Count_ByContentType()
+ {
+ const int itemCount = 1000; // v1.2: Standardized to 1000
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"Count_{i}", -1);
+ ContentService.Save(content);
+ }
+
+ int count = 0;
+ MeasureAndRecord("Count_ByContentType", itemCount, () =>
+ {
+ count = ContentService.Count(ContentType.Alias);
+ });
+
+ // Note: base class may create some content too
+ Assert.That(count, Is.GreaterThanOrEqualTo(itemCount));
+ }
+
+ ///
+ /// Benchmark 12: Count descendants (1000 descendants).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe. Standardized from 500 to 1000.
+ [Test]
+ [LongRunning]
+ public void Benchmark_CountDescendants_LargeTree()
+ {
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "CountDescParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 1000; // v1.2: Standardized to 1000
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"CountDescChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ int count = 0;
+ MeasureAndRecord("CountDescendants_LargeTree", childCount, () =>
+ {
+ count = ContentService.CountDescendants(parent.Id);
+ });
+
+ Assert.That(count, Is.EqualTo(childCount));
+ }
+
+ ///
+ /// Benchmark 13: HasChildren called 100 times (repeated single lookups).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_HasChildren_100Nodes()
+ {
+ const int nodeCount = 100;
+ var nodes = new List();
+
+ // Create nodes, half with children, half without
+ for (var i = 0; i < nodeCount; i++)
+ {
+ var node = ContentBuilder.CreateSimpleContent(ContentType, $"HasChildren_{i}", -1);
+ ContentService.Save(node);
+ nodes.Add(node);
+
+ if (i % 2 == 0)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"Child_{i}", node.Id);
+ ContentService.Save(child);
+ }
+ }
+
+ int trueCount = 0;
+ MeasureAndRecord("HasChildren_100Nodes", nodeCount, () =>
+ {
+ foreach (var node in nodes)
+ {
+ if (ContentService.HasChildren(node.Id))
+ {
+ trueCount++;
+ }
+ }
+ });
+
+ Assert.That(trueCount, Is.EqualTo(50));
+ }
+
+ #endregion
+
+ #region Publish Operation Benchmarks (7 tests)
+
+ ///
+ /// Benchmark 14: Single item publish.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Publish_SingleItem()
+ {
+ // v1.2: Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_PublishSingle", -1);
+ ContentService.Save(warmupContent);
+ ContentService.Publish(warmupContent, new[] { "*" });
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "PublishSingle", -1);
+ ContentService.Save(content);
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Publish(content, new[] { "*" });
+ sw.Stop();
+ RecordBenchmark("Publish_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Published, Is.True);
+ }
+
+ ///
+ /// Benchmark 15: Publish 100 items sequentially.
+ ///
+ /// v1.2: Renamed from BatchOf50 to BatchOf100 for standardization.
+ [Test]
+ [LongRunning]
+ public void Benchmark_Publish_BatchOf100()
+ {
+ const int itemCount = 100; // v1.2: Standardized to 100
+
+ // v1.2: Warmup with throwaway batch
+ var warmupItems = new List();
+ for (var i = 0; i < 10; i++) // Small warmup batch for JIT
+ {
+ var warmup = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_PublishBatch_{i}", -1);
+ ContentService.Save(warmup);
+ warmupItems.Add(warmup);
+ }
+ foreach (var warmup in warmupItems)
+ {
+ ContentService.Publish(warmup, new[] { "*" });
+ }
+
+ // Measured run with fresh batch
+ var items = new List();
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"PublishBatch_{i}", -1);
+ ContentService.Save(content);
+ items.Add(content);
+ }
+
+ var sw = Stopwatch.StartNew();
+ foreach (var content in items)
+ {
+ ContentService.Publish(content, new[] { "*" });
+ }
+ sw.Stop();
+ RecordBenchmark("Publish_BatchOf100", sw.ElapsedMilliseconds, itemCount);
+
+ Assert.That(items.All(c => c.Published), Is.True);
+ }
+
+ ///
+ /// Benchmark 16: PublishBranch with shallow tree (1 parent + 100 children).
+ ///
+ /// v1.2: Standardized from 20 to 100 children.
+ [Test]
+ [LongRunning]
+ public void Benchmark_PublishBranch_ShallowTree()
+ {
+ // v1.2: Warmup with throwaway tree
+ var warmupParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_BranchParent", -1);
+ ContentService.Save(warmupParent);
+ for (var i = 0; i < 10; i++) // Small warmup tree
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_BranchChild_{i}", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ }
+ ContentService.PublishBranch(warmupParent, PublishBranchFilter.Default, new[] { "*" });
+
+ // Measured run with fresh tree
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "BranchParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"BranchChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.PublishBranch(parent, PublishBranchFilter.Default, new[] { "*" });
+ sw.Stop();
+ RecordBenchmark("PublishBranch_ShallowTree", sw.ElapsedMilliseconds, childCount + 1);
+
+ Assert.That(parent.Published, Is.True);
+ }
+
+ ///
+ /// Benchmark 17: PublishBranch with deep tree (5 levels, 100 items total).
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_PublishBranch_DeepTree()
+ {
+ // v1.2: Warmup with small deep tree (3 levels, 3 items each)
+ var warmupRoot = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_DeepBranchRoot", -1);
+ ContentService.Save(warmupRoot);
+ var warmupParent = warmupRoot;
+ for (var level = 0; level < 3; level++)
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_DeepLevel{level}_0", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ warmupParent = warmupChild;
+ }
+ ContentService.PublishBranch(warmupRoot, PublishBranchFilter.Default, new[] { "*" });
+
+ // Measured run with fresh deep tree
+ var root = ContentBuilder.CreateSimpleContent(ContentType, "DeepBranchRoot", -1);
+ ContentService.Save(root);
+
+ // Create 5 levels, 20 items each level
+ var currentParent = root;
+ for (var level = 0; level < 5; level++)
+ {
+ var firstChild = ContentBuilder.CreateSimpleContent(ContentType, $"DeepLevel{level}_0", currentParent.Id);
+ ContentService.Save(firstChild);
+
+ for (var i = 1; i < 20; i++)
+ {
+ var sibling = ContentBuilder.CreateSimpleContent(ContentType, $"DeepLevel{level}_{i}", currentParent.Id);
+ ContentService.Save(sibling);
+ }
+
+ currentParent = firstChild;
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.PublishBranch(root, PublishBranchFilter.Default, new[] { "*" });
+ sw.Stop();
+ RecordBenchmark("PublishBranch_DeepTree", sw.ElapsedMilliseconds, 101);
+
+ Assert.That(root.Published, Is.True);
+ }
+
+ ///
+ /// Benchmark 18: Single item unpublish.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Unpublish_SingleItem()
+ {
+ // v1.2: Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_UnpublishTest", -1);
+ ContentService.Save(warmupContent);
+ ContentService.Publish(warmupContent, new[] { "*" });
+ ContentService.Unpublish(warmupContent);
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "UnpublishTest", -1);
+ ContentService.Save(content);
+ ContentService.Publish(content, new[] { "*" });
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Unpublish(content);
+ sw.Stop();
+ RecordBenchmark("Unpublish_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Published, Is.False);
+ }
+
+ ///
+ /// Benchmark 19: PerformScheduledPublish with 100 scheduled items.
+ ///
+ /// v1.2: Standardized from 50 to 100 items.
+ [Test]
+ [LongRunning]
+ public void Benchmark_PerformScheduledPublish()
+ {
+ const int itemCount = 100; // v1.2: Standardized to 100
+
+ // v1.2: Warmup with small set of scheduled items
+ for (var i = 0; i < 10; i++)
+ {
+ var warmup = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_Scheduled_{i}", -1);
+ var warmupSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-10), null);
+ ContentService.Save(warmup, -1, warmupSchedule);
+ }
+ ContentService.PerformScheduledPublish(DateTime.UtcNow.AddMinutes(-9));
+
+ // Create measured items with schedules in the past (ready for publish)
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"Scheduled_{i}", -1);
+ var schedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
+ ContentService.Save(content, -1, schedule);
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.PerformScheduledPublish(DateTime.UtcNow);
+ sw.Stop();
+ RecordBenchmark("PerformScheduledPublish", sw.ElapsedMilliseconds, itemCount);
+ }
+
+ ///
+ /// Benchmark 20: GetContentSchedulesByIds for 100 items (N+1 hotspot).
+ ///
+ /// v1.2: Read-only operation - MeasureAndRecord warmup is safe.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetContentSchedulesByIds_100Items()
+ {
+ const int itemCount = 100;
+ var keys = new List();
+
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"Schedule_{i}", -1);
+ var schedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddDays(1), null);
+ ContentService.Save(content, -1, schedule);
+ keys.Add(content.Key);
+ }
+
+ IDictionary>? results = null;
+ MeasureAndRecord("GetContentSchedulesByIds_100Items", itemCount, () =>
+ {
+ results = ContentService.GetContentSchedulesByIds(keys.ToArray());
+ });
+
+ Assert.That(results, Is.Not.Null);
+ }
+
+ #endregion
+
+ #region Move Operation Benchmarks (8 tests)
+
+ ///
+ /// Benchmark 21: Single item move.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Move_SingleItem()
+ {
+ // v1.2: Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_MoveTest", -1);
+ ContentService.Save(warmupContent);
+ var warmupTarget = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_MoveTarget", -1);
+ ContentService.Save(warmupTarget);
+ ContentService.Move(warmupContent, warmupTarget.Id);
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "MoveTest", -1);
+ ContentService.Save(content);
+ var newParent = ContentBuilder.CreateSimpleContent(ContentType, "MoveTarget", -1);
+ ContentService.Save(newParent);
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Move(content, newParent.Id);
+ sw.Stop();
+ RecordBenchmark("Move_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.ParentId, Is.EqualTo(newParent.Id));
+ }
+
+ ///
+ /// Benchmark 22: Move item with 100 descendants.
+ ///
+ /// v1.2: Standardized from 50 to 100 descendants.
+ [Test]
+ [LongRunning]
+ public void Benchmark_Move_WithDescendants()
+ {
+ // v1.2: Warmup with small tree
+ var warmupParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_MoveParent", -1);
+ ContentService.Save(warmupParent);
+ for (var i = 0; i < 10; i++)
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_MoveChild_{i}", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ }
+ var warmupNewParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_MoveDescTarget", -1);
+ ContentService.Save(warmupNewParent);
+ ContentService.Move(warmupParent, warmupNewParent.Id);
+
+ // Measured run with fresh tree
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "MoveParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"MoveChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ var newParent = ContentBuilder.CreateSimpleContent(ContentType, "MoveDescTarget", -1);
+ ContentService.Save(newParent);
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Move(parent, newParent.Id);
+ sw.Stop();
+ RecordBenchmark("Move_WithDescendants", sw.ElapsedMilliseconds, childCount + 1);
+
+ Assert.That(parent.ParentId, Is.EqualTo(newParent.Id));
+ }
+
+ ///
+ /// Benchmark 23: MoveToRecycleBin for published item.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_MoveToRecycleBin_Published()
+ {
+ // v1.2: Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_RecycleBinPublished", -1);
+ ContentService.Save(warmupContent);
+ ContentService.Publish(warmupContent, new[] { "*" });
+ ContentService.MoveToRecycleBin(warmupContent);
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "RecycleBinPublished", -1);
+ ContentService.Save(content);
+ ContentService.Publish(content, new[] { "*" });
+
+ var sw = Stopwatch.StartNew();
+ ContentService.MoveToRecycleBin(content);
+ sw.Stop();
+ RecordBenchmark("MoveToRecycleBin_Published", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Trashed, Is.True);
+ }
+
+ ///
+ /// Benchmark 24: MoveToRecycleBin for large tree (1000 descendants).
+ ///
+ /// v1.2: Standardized from 100 to 1000 descendants.
+ [Test]
+ [LongRunning]
+ public void Benchmark_MoveToRecycleBin_LargeTree()
+ {
+ // v1.2: Warmup with small tree
+ var warmupParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_RecycleLargeParent", -1);
+ ContentService.Save(warmupParent);
+ for (var i = 0; i < 10; i++)
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_RecycleLargeChild_{i}", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ }
+ ContentService.MoveToRecycleBin(warmupParent);
+
+ // Measured run with fresh tree
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "RecycleLargeParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 1000; // v1.2: Standardized to 1000
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"RecycleLargeChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ var sw = Stopwatch.StartNew();
+ ContentService.MoveToRecycleBin(parent);
+ sw.Stop();
+ RecordBenchmark("MoveToRecycleBin_LargeTree", sw.ElapsedMilliseconds, childCount + 1);
+
+ Assert.That(parent.Trashed, Is.True);
+ }
+
+ ///
+ /// Benchmark 25: Single item copy.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Copy_SingleItem()
+ {
+ // v1.2: Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_CopyTest", -1);
+ ContentService.Save(warmupContent);
+ var warmupTarget = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_CopyTarget", -1);
+ ContentService.Save(warmupTarget);
+ ContentService.Copy(warmupContent, warmupTarget.Id, false);
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "CopyTest", -1);
+ ContentService.Save(content);
+ var copyTarget = ContentBuilder.CreateSimpleContent(ContentType, "CopyTarget", -1);
+ ContentService.Save(copyTarget);
+
+ IContent? copy = null;
+ var sw = Stopwatch.StartNew();
+ copy = ContentService.Copy(content, copyTarget.Id, false);
+ sw.Stop();
+ RecordBenchmark("Copy_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(copy, Is.Not.Null);
+ }
+
+ ///
+ /// Benchmark 26: Recursive copy of 100 items.
+ ///
+ /// v1.2: Renamed from 50Items to 100Items for standardization.
+ [Test]
+ [LongRunning]
+ public void Benchmark_Copy_Recursive_100Items()
+ {
+ // v1.2: Warmup with small tree
+ var warmupParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_CopyRecParent", -1);
+ ContentService.Save(warmupParent);
+ for (var i = 0; i < 10; i++)
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_CopyRecChild_{i}", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ }
+ var warmupCopyTarget = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_CopyRecTarget", -1);
+ ContentService.Save(warmupCopyTarget);
+ ContentService.Copy(warmupParent, warmupCopyTarget.Id, false, true);
+
+ // Measured run with fresh tree
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "CopyRecParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"CopyRecChild_{i}", parent.Id);
+ ContentService.Save(child);
+ }
+
+ var copyTarget = ContentBuilder.CreateSimpleContent(ContentType, "CopyRecTarget", -1);
+ ContentService.Save(copyTarget);
+
+ IContent? copy = null;
+ var sw = Stopwatch.StartNew();
+ copy = ContentService.Copy(parent, copyTarget.Id, false, true);
+ sw.Stop();
+ RecordBenchmark("Copy_Recursive_100Items", sw.ElapsedMilliseconds, childCount + 1);
+
+ Assert.That(copy, Is.Not.Null);
+ }
+
+ ///
+ /// Benchmark 27: Sort 100 children.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Sort_100Children()
+ {
+ // v1.2: Warmup with small tree
+ var warmupParent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_SortParent", -1);
+ ContentService.Save(warmupParent);
+ var warmupChildren = new List();
+ for (var i = 0; i < 10; i++)
+ {
+ var warmupChild = ContentBuilder.CreateSimpleContent(ContentType, $"Warmup_SortChild_{i}", warmupParent.Id);
+ ContentService.Save(warmupChild);
+ warmupChildren.Add(warmupChild);
+ }
+ warmupChildren.Reverse();
+ ContentService.Sort(warmupChildren);
+
+ // Measured run with fresh tree
+ var parent = ContentBuilder.CreateSimpleContent(ContentType, "SortParent", -1);
+ ContentService.Save(parent);
+
+ const int childCount = 100;
+ var children = new List();
+ for (var i = 0; i < childCount; i++)
+ {
+ var child = ContentBuilder.CreateSimpleContent(ContentType, $"SortChild_{i}", parent.Id);
+ ContentService.Save(child);
+ children.Add(child);
+ }
+
+ // Reverse the order
+ children.Reverse();
+
+ var sw = Stopwatch.StartNew();
+ ContentService.Sort(children);
+ sw.Stop();
+ RecordBenchmark("Sort_100Children", sw.ElapsedMilliseconds, childCount);
+ }
+
+ ///
+ /// Benchmark 28: EmptyRecycleBin with 100 items.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_EmptyRecycleBin_100Items()
+ {
+ const int itemCount = 100;
+ for (var i = 0; i < itemCount; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"Trash_{i}", -1);
+ ContentService.Save(content);
+ ContentService.MoveToRecycleBin(content);
+ }
+
+ MeasureAndRecord("EmptyRecycleBin_100Items", itemCount, () =>
+ {
+ ContentService.EmptyRecycleBin();
+ }, skipWarmup: true); // Destructive operation - cannot repeat
+
+ Assert.That(ContentService.RecycleBinSmells(), Is.False);
+ }
+
+ #endregion
+
+ #region Version Operation Benchmarks (4 tests)
+
+ ///
+ /// Benchmark 29: GetVersions for item with 100 versions.
+ ///
+ /// v1.2: Renamed from 50Versions to 100Versions for standardization. Read-only operation.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetVersions_ItemWith100Versions()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "VersionTest", -1);
+ ContentService.Save(content);
+
+ // Create 100 versions by saving repeatedly
+ const int versionCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < versionCount; i++)
+ {
+ content.Name = $"VersionTest_v{i}";
+ ContentService.Save(content);
+ }
+
+ IEnumerable? versions = null;
+ MeasureAndRecord("GetVersions_ItemWith100Versions", versionCount, () =>
+ {
+ versions = ContentService.GetVersions(content.Id);
+ });
+
+ Assert.That(versions!.Count(), Is.GreaterThanOrEqualTo(versionCount));
+ }
+
+ ///
+ /// Benchmark 30: GetVersionsSlim with paging (100 versions, page of 10).
+ ///
+ /// v1.2: Standardized from 50 to 100 versions. Read-only operation.
+ [Test]
+ [LongRunning]
+ public void Benchmark_GetVersionsSlim_Paged()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "SlimVersionTest", -1);
+ ContentService.Save(content);
+
+ // Create 100 versions
+ const int versionCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < versionCount; i++)
+ {
+ content.Name = $"SlimVersionTest_v{i}";
+ ContentService.Save(content);
+ }
+
+ IEnumerable? versions = null;
+ MeasureAndRecord("GetVersionsSlim_Paged", 10, () =>
+ {
+ versions = ContentService.GetVersionsSlim(content.Id, 0, 10);
+ });
+
+ Assert.That(versions!.Count(), Is.EqualTo(10));
+ }
+
+ ///
+ /// Benchmark 31: Rollback to previous version.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_Rollback_ToVersion()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "RollbackTest", -1);
+ ContentService.Save(content);
+
+ // Create 10 versions
+ for (var i = 0; i < 10; i++)
+ {
+ content.Name = $"RollbackTest_v{i}";
+ ContentService.Save(content);
+ }
+
+ var versions = ContentService.GetVersions(content.Id).ToList();
+ // v1.2: Defensive assertion and relative indexing to avoid index out of range
+ Assert.That(versions.Count, Is.GreaterThanOrEqualTo(6), "Need at least 6 versions for rollback test");
+ var targetVersionId = versions[versions.Count / 2].VersionId; // Rollback to middle version
+
+ MeasureAndRecord("Rollback_ToVersion", 1, () =>
+ {
+ ContentService.Rollback(content.Id, targetVersionId);
+ }, skipWarmup: true); // Modifying operation - results differ on repeat
+ }
+
+ ///
+ /// Benchmark 32: DeleteVersions by date (100 versions).
+ ///
+ /// v1.2: Standardized from 50 to 100 versions.
+ [Test]
+ [LongRunning]
+ public void Benchmark_DeleteVersions_ByDate()
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "DeleteVersionsTest", -1);
+ ContentService.Save(content);
+
+ // Create 100 versions
+ const int versionCount = 100; // v1.2: Standardized to 100
+ for (var i = 0; i < versionCount; i++)
+ {
+ content.Name = $"DeleteVersionsTest_v{i}";
+ ContentService.Save(content);
+ }
+
+ // Delete all versions before "now" (which should be all of them)
+ MeasureAndRecord("DeleteVersions_ByDate", versionCount, () =>
+ {
+ ContentService.DeleteVersions(content.Id, DateTime.UtcNow.AddMinutes(1));
+ }, skipWarmup: true); // Destructive operation - cannot repeat
+ }
+
+ #endregion
+
+ #region Baseline Comparison (1 test)
+
+ ///
+ /// Benchmark 33: Meta-benchmark for comparison validation.
+ /// This test runs a representative sample and outputs summary statistics.
+ ///
+ ///
+ /// v1.2: Uses manual Stopwatch timing (not MeasureAndRecord) because this benchmark
+ /// times a composite sequence of operations (save, publish, query, trash, empty)
+ /// to measure overall system performance, not individual operation latency.
+ ///
+ [Test]
+ [LongRunning]
+ public void Benchmark_BaselineComparison()
+ {
+ // This test exists to provide a consistent comparison point.
+ // It runs a simple operation sequence that represents typical usage.
+ // v1.2: Manual timing used for composite operation measurement
+
+ var sw = Stopwatch.StartNew();
+
+ // Create 10 items
+ var items = new List();
+ for (var i = 0; i < 10; i++)
+ {
+ var content = ContentBuilder.CreateSimpleContent(ContentType, $"Baseline_{i}", -1);
+ ContentService.Save(content);
+ items.Add(content);
+ }
+
+ // Publish all
+ foreach (var item in items)
+ {
+ ContentService.Publish(item, new[] { "*" });
+ }
+
+ // Query
+ var count = ContentService.Count(ContentType.Alias);
+
+ // Move to recycle bin
+ foreach (var item in items)
+ {
+ ContentService.MoveToRecycleBin(item);
+ }
+
+ // Empty recycle bin
+ ContentService.EmptyRecycleBin();
+
+ sw.Stop();
+
+ RecordBenchmark("BaselineComparison", sw.ElapsedMilliseconds, 10);
+
+ TestContext.WriteLine($"[BASELINE] Total time for representative operations: {sw.ElapsedMilliseconds}ms");
+ }
+
+ #endregion
+}
+```
+
+**Step 2: Run build to verify benchmark file compiles**
+
+Run: `dotnet build tests/Umbraco.Tests.Integration`
+Expected: Build succeeds
+
+**Step 3: Commit**
+
+```bash
+git add tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringBenchmarks.cs
+git commit -m "$(cat <<'EOF'
+test: add ContentServiceRefactoringBenchmarks for Phase 0 baseline
+
+Adds 33 performance benchmarks organized by operation type:
+- 7 CRUD operation benchmarks
+- 6 query operation benchmarks
+- 7 publish operation benchmarks
+- 8 move operation benchmarks
+- 4 version operation benchmarks
+- 1 baseline comparison meta-benchmark
+
+Benchmarks output JSON for automated comparison between phases.
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 8: Create ContentServiceBaseTests.cs
+
+**Files:**
+- Create: `tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/ContentServiceBaseTests.cs`
+
+**Step 1: Write the unit test file**
+
+Note: ContentServiceBase doesn't exist yet - it will be created in Phase 1. These tests establish the expected contract for the base class.
+
+```csharp
+// Copyright (c) Umbraco.
+// See LICENSE for more details.
+
+using Microsoft.Extensions.Logging;
+using Moq;
+using NUnit.Framework;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Persistence.Repositories;
+using Umbraco.Cms.Core.Scoping;
+using Umbraco.Cms.Core.Services;
+
+namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Infrastructure.Services;
+
+///
+/// Unit tests for ContentServiceBase (shared infrastructure for extracted services).
+/// These tests establish the expected contract for the base class before it's created.
+///
+///
+/// ContentServiceBase will be created in Phase 1. These tests validate the design requirements:
+/// - Audit helper method behavior
+/// - Scope provider access patterns
+/// - Logger injection patterns
+///
+[TestFixture]
+public class ContentServiceBaseTests
+{
+ // Note: These tests will be uncommented when ContentServiceBase is created in Phase 1.
+ // For now, they serve as documentation of the expected behavior.
+
+ /*
+ private Mock _scopeProviderMock;
+ private Mock _auditServiceMock;
+ private Mock _eventMessagesFactoryMock;
+ private Mock> _loggerMock;
+ private TestContentService _service;
+
+ [SetUp]
+ public void Setup()
+ {
+ _scopeProviderMock = new Mock();
+ _auditServiceMock = new Mock();
+ _eventMessagesFactoryMock = new Mock();
+ _loggerMock = new Mock>();
+
+ _eventMessagesFactoryMock.Setup(x => x.Get()).Returns(new EventMessages());
+
+ _service = new TestContentService(
+ _scopeProviderMock.Object,
+ _auditServiceMock.Object,
+ _eventMessagesFactoryMock.Object,
+ _loggerMock.Object);
+ }
+
+ #region Audit Helper Method Tests
+
+ [Test]
+ public void Audit_WithValidParameters_CreatesAuditEntry()
+ {
+ // Arrange
+ var userId = 1;
+ var objectId = 100;
+ var message = "Test audit message";
+
+ // Act
+ _service.TestAudit(AuditType.Save, userId, objectId, message);
+
+ // Assert
+ _auditServiceMock.Verify(x => x.Write(
+ userId,
+ message,
+ It.IsAny(),
+ objectId), Times.Once);
+ }
+
+ [Test]
+ public void Audit_WithNullMessage_UsesDefaultMessage()
+ {
+ // Arrange
+ var userId = 1;
+ var objectId = 100;
+
+ // Act
+ _service.TestAudit(AuditType.Save, userId, objectId, null);
+
+ // Assert
+ _auditServiceMock.Verify(x => x.Write(
+ userId,
+ It.Is(s => !string.IsNullOrEmpty(s)),
+ It.IsAny(),
+ objectId), Times.Once);
+ }
+
+ #endregion
+
+ #region Scope Provider Access Pattern Tests
+
+ [Test]
+ public void CreateScope_ReturnsValidCoreScope()
+ {
+ // Arrange
+ var scopeMock = new Mock();
+ _scopeProviderMock.Setup(x => x.CreateCoreScope(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()))
+ .Returns(scopeMock.Object);
+
+ // Act
+ var scope = _service.TestCreateScope();
+
+ // Assert
+ Assert.That(scope, Is.Not.Null);
+ _scopeProviderMock.Verify(x => x.CreateCoreScope(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()), Times.Once);
+ }
+
+ [Test]
+ public void CreateScope_WithAmbientScope_ReusesExisting()
+ {
+ // Arrange
+ var ambientScopeMock = new Mock();
+ _scopeProviderMock.SetupGet(x => x.AmbientScope).Returns(ambientScopeMock.Object);
+
+ // When ambient scope exists, CreateCoreScope should still be called
+ // but the scope provider handles the nesting
+ _scopeProviderMock.Setup(x => x.CreateCoreScope(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()))
+ .Returns(ambientScopeMock.Object);
+
+ // Act
+ var scope = _service.TestCreateScope();
+
+ // Assert - scope should be the ambient scope (or nested in it)
+ Assert.That(scope, Is.Not.Null);
+ }
+
+ #endregion
+
+ #region Logger Injection Tests
+
+ [Test]
+ public void Logger_IsInjectedCorrectly()
+ {
+ // Assert
+ Assert.That(_service.TestLogger, Is.Not.Null);
+ Assert.That(_service.TestLogger, Is.EqualTo(_loggerMock.Object));
+ }
+
+ [Test]
+ public void Logger_UsesCorrectCategoryName()
+ {
+ // The logger should be typed to the concrete service class
+ // This is verified by the generic type parameter
+ Assert.That(_service.TestLogger, Is.InstanceOf>());
+ }
+
+ #endregion
+
+ #region Repository Access Tests
+
+ [Test]
+ public void DocumentRepository_IsAccessibleWithinScope()
+ {
+ // This test validates that the base class provides access to the document repository
+ // The actual repository access pattern will be tested in integration tests
+ Assert.Pass("Repository access validated in integration tests");
+ }
+
+ #endregion
+
+ ///
+ /// Test implementation of ContentServiceBase for unit testing.
+ ///
+ private class TestContentService : ContentServiceBase
+ {
+ public TestContentService(
+ ICoreScopeProvider scopeProvider,
+ IAuditService auditService,
+ IEventMessagesFactory eventMessagesFactory,
+ ILogger logger)
+ : base(scopeProvider, auditService, eventMessagesFactory, logger)
+ {
+ }
+
+ // Expose protected members for testing
+ public void TestAudit(AuditType type, int userId, int objectId, string? message)
+ => Audit(type, userId, objectId, message);
+
+ public ICoreScope TestCreateScope() => ScopeProvider.CreateCoreScope();
+
+ public ILogger TestLogger => Logger;
+ }
+ */
+
+ ///
+ /// v1.3: Tracking test that fails when ContentServiceBase is created.
+ /// When this test fails, uncomment all tests in this file and delete this placeholder.
+ ///
+ [Test]
+ public void ContentServiceBase_WhenCreated_UncommentTests()
+ {
+ // This tracking test uses reflection to detect when ContentServiceBase is created.
+ // When you see this test fail, it means Phase 1 has created ContentServiceBase.
+ // At that point:
+ // 1. Uncomment all the tests in this file (the commented section above)
+ // 2. Delete this tracking test
+ // 3. Verify all tests pass
+
+ var type = Type.GetType("Umbraco.Cms.Infrastructure.Services.ContentServiceBase, Umbraco.Infrastructure");
+
+ Assert.That(type, Is.Null,
+ "ContentServiceBase now exists! Uncomment all tests in this file and delete this tracking test.");
+ }
+}
+```
+
+**Step 2: Run build to verify test file compiles**
+
+Run: `dotnet build tests/Umbraco.Tests.UnitTests`
+Expected: Build succeeds
+
+**Step 3: Commit**
+
+```bash
+git add tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/ContentServiceBaseTests.cs
+git commit -m "$(cat <<'EOF'
+test: add ContentServiceBaseTests skeleton for Phase 0
+
+Adds unit test file for ContentServiceBase with documented test cases.
+Tests are commented out until ContentServiceBase is created in Phase 1:
+- 2 audit helper method tests
+- 2 scope provider access pattern tests
+- 2 logger injection tests
+- 1 repository access test
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 9: Run All Tests and Verify
+
+**Files:**
+- Update: `tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs` (v1.2: documentation update)
+
+**Step 0: Update ContentServiceBenchmarkBase.cs documentation (v1.2)**
+
+In `ContentServiceBenchmarkBase.cs`, update the `MeasureAndRecord` method documentation to clarify read-only usage intent:
+
+```csharp
+///
+/// Measures and records a benchmark, returning the result of the function.
+///
+///
+/// v1.2: This overload does NOT include warmup because it returns a value.
+/// Use only for read-only operations (GetById, GetByIds, etc.) that can
+/// safely be repeated without side effects. The caller is responsible for
+/// ensuring warmup occurs separately if needed.
+///
+protected T MeasureAndRecord(string name, int itemCount, Func func)
+```
+
+**Step 1: Run all 15 integration tests**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringTests" -v n`
+Expected: All 15 tests PASS
+
+**Step 2: Verify benchmark file compiles and runs (one sample)**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceRefactoringBenchmarks.Benchmark_Save_SingleItem" -v n --logger "console;verbosity=detailed"`
+Expected: Test PASSES with benchmark output
+
+**Step 3: Run unit tests**
+
+Run: `dotnet test tests/Umbraco.Tests.UnitTests --filter "FullyQualifiedName~ContentServiceBaseTests" -v n`
+Expected: 1 placeholder test PASSES
+
+---
+
+## Task 10: Capture Baseline Benchmarks
+
+**Files:**
+- Create: `docs/plans/baseline-phase0.json` (output file)
+
+**Step 1: Run full benchmark suite**
+
+Run:
+```bash
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "Category=Benchmark&FullyQualifiedName~ContentServiceRefactoringBenchmarks" \
+ --logger "console;verbosity=detailed" 2>&1 | tee benchmark-$(git rev-parse --short HEAD).txt
+```
+
+Expected: All 33 benchmarks complete (this may take several minutes)
+
+**Step 2: Extract JSON results**
+
+Run (using POSIX-compliant sed for cross-platform compatibility):
+```bash
+# v1.2: Explicit error handling instead of silent fallback
+sed -n 's/.*\[BENCHMARK_JSON\]\(.*\)\[\/BENCHMARK_JSON\].*/\1/p' benchmark-*.txt > docs/plans/baseline-phase0.json
+if [ ! -s docs/plans/baseline-phase0.json ]; then
+ echo "ERROR: No benchmark JSON data found in benchmark-*.txt files"
+ echo "Check that benchmarks ran successfully and output [BENCHMARK_JSON] markers"
+ exit 1
+fi
+
+# v1.3: Optional JSON validation (requires jq)
+if command -v jq &> /dev/null; then
+ if jq empty docs/plans/baseline-phase0.json 2>/dev/null; then
+ echo "JSON validation passed"
+ else
+ echo "WARNING: baseline-phase0.json may contain invalid JSON"
+ echo "Review the file manually before committing"
+ fi
+else
+ echo "NOTE: jq not installed, skipping JSON validation"
+fi
+```
+
+**Step 3: Create git tag for Phase 0 baseline**
+
+Run:
+```bash
+git tag phase-0-baseline -m "Phase 0 baseline: test infrastructure complete"
+```
+
+**Step 4: Commit baseline file**
+
+```bash
+git add docs/plans/baseline-phase0.json benchmark-*.txt
+git commit -m "$(cat <<'EOF'
+chore: capture Phase 0 baseline benchmarks
+
+Records baseline performance metrics for ContentService operations
+before refactoring begins. This data will be used to detect
+regressions during subsequent phases.
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 11: Final Verification and Summary
+
+**Files:**
+- None (verification only)
+
+**Step 1: Verify all files exist**
+
+Run:
+```bash
+ls -la tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringTests.cs
+ls -la tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentServiceRefactoringBenchmarks.cs
+ls -la tests/Umbraco.Tests.UnitTests/Umbraco.Infrastructure/Services/ContentServiceBaseTests.cs
+ls -la tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs
+```
+
+Expected: All 4 files exist
+
+**Step 2: Run full ContentService test suite (phase gate)**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentService" -v n`
+Expected: All ContentService tests PASS (including new refactoring tests)
+
+**Step 3: Verify git tags**
+
+Run: `git tag -l "phase-*"`
+Expected: `phase-0-baseline` tag exists
+
+---
+
+## Phase 0 Completion Checklist
+
+- [ ] ContentServiceBenchmarkBase.cs committed (Task 0)
+ - [ ] MeasureAndRecord includes warmup (v1.3)
+- [ ] ContentServiceRefactoringTests.cs created with 15 integration tests
+ - [ ] 2 notification ordering tests
+ - [ ] 3 sort operation tests
+ - [ ] 3 DeleteOfType tests
+ - [ ] 4 permission tests
+ - [ ] 3 transaction boundary tests
+- [ ] ContentServiceRefactoringBenchmarks.cs created with 33 benchmarks
+ - [ ] 7 CRUD operation benchmarks
+ - [ ] 6 query operation benchmarks
+ - [ ] 7 publish operation benchmarks
+ - [ ] 8 move operation benchmarks
+ - [ ] 4 version operation benchmarks
+ - [ ] 1 baseline comparison test
+- [ ] ContentServiceBaseTests.cs created (7 tests documented, tracking test active)
+ - [ ] v1.3: Tracking test that fails when ContentServiceBase is created
+- [ ] All 15 integration tests pass
+- [ ] Baseline benchmarks captured
+- [ ] Git tag `phase-0-baseline` created
+- [ ] Baseline JSON committed to repository
+
+**Gate:** All tests pass, baseline captured, tagged commit created.
+
+---
+
+## Execution Notes
+
+- **Total tasks:** 12 (Task 0-11)
+- **Estimated steps:** ~47 individual steps
+- **Test count:** 15 integration tests + 33 benchmarks + 1 tracking unit test = 49 tests
+- **Key risk:** Benchmark tests may take 10+ minutes to complete - run with patience
+- **Rollback:** If any step fails, use `git checkout .` to restore files
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-1.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-1.md
new file mode 100644
index 0000000000..4183147c23
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-1.md
@@ -0,0 +1,480 @@
+# Critical Implementation Review: Phase 1 ContentService CRUD Extraction
+
+**Reviewed:** 2025-12-20
+**Plan:** `docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md`
+**Reviewer:** Claude (Senior Staff Engineer perspective)
+**Status:** ⚠️ Approve with Changes
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- Clear task-by-task structure with TDD approach (write failing tests first)
+- Correct identification of methods to extract (Create, GetById, Save, Delete)
+- Follows existing Umbraco patterns (RepositoryService base, scoping, notifications)
+- Preserves notification system behavior (ContentSavingNotification, ContentDeletedNotification, etc.)
+- Maintains behavioral parity with existing ContentService for core operations
+- Proper use of dependency injection and interface-first design
+
+### Major Concerns
+
+- Nested scope issues in delete cascade operations
+- Potential DI circular dependency when ContentService depends on IContentCrudService
+- Missing behavioral parity in several edge cases
+- Bug in batch Save audit message (copies existing bug but perpetuates it)
+- Interface missing key read operations (GetAncestors, GetPagedChildren, GetPagedDescendants)
+
+---
+
+## 2. Critical Issues
+
+### 2.1 Nested Scope Anti-Pattern in Delete Cascade
+
+**Location:** `ContentCrudService.cs` lines 784-831
+
+**Description:** `DeleteLocked` (line 784-805) calls `GetPagedDescendants` (line 810-831), which creates a NEW scope inside the already-open scope from `Delete` (line 754).
+
+```csharp
+// Delete creates scope at line 754
+using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+{
+ // ...
+ DeleteLocked(scope, content, eventMessages); // line 772
+}
+
+// DeleteLocked calls GetPagedDescendants at line 797
+IEnumerable descendants = GetPagedDescendants(content.Id, 0, pageSize, out total);
+
+// GetPagedDescendants creates ANOTHER scope at line 812
+private IEnumerable GetPagedDescendants(...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true)) // NESTED!
+ {
+ scope.ReadLock(Constants.Locks.ContentTree);
+ // ...
+ }
+}
+```
+
+**Why it matters:**
+- Redundant read locks on the same resource (`Constants.Locks.ContentTree`)
+- Potential deadlock scenarios under high concurrency
+- Performance overhead from scope creation/disposal
+- Violates single responsibility - helper method shouldn't manage its own transaction
+
+**Required Fix:** The private `GetPagedDescendants` should NOT create its own scope. It's only called from `DeleteLocked`, which already holds a scope. Refactor to:
+
+```csharp
+///
+/// Gets paged descendants for internal use. MUST be called within an existing scope.
+///
+private IEnumerable GetPagedDescendantsLocked(int id, long pageIndex, int pageSize, out long totalRecords)
+{
+ // No scope creation - assumes caller holds scope with proper locks
+ if (id != Constants.System.Root)
+ {
+ var contentPath = _entityRepository.GetAllPaths(Constants.ObjectTypes.Document, id).FirstOrDefault();
+ if (contentPath == null)
+ {
+ totalRecords = 0;
+ return Enumerable.Empty();
+ }
+
+ IQuery? query = Query();
+ query?.Where(x => x.Path.SqlStartsWith($"{contentPath.Path},", TextColumnType.NVarchar));
+ return DocumentRepository.GetPage(query, pageIndex, pageSize, out totalRecords, null, Ordering.By("Path", Direction.Descending));
+ }
+
+ return DocumentRepository.GetPage(null, pageIndex, pageSize, out totalRecords, null, Ordering.By("Path", Direction.Descending));
+}
+```
+
+Update `DeleteLocked` to call `GetPagedDescendantsLocked` instead.
+
+---
+
+### 2.2 Circular Dependency Risk in DI
+
+**Location:** Task 5, lines 1073-1074 of the plan
+
+**Description:** Task 5 injects `IContentCrudService` into `ContentService`. But the obsolete constructors chain via `StaticServiceProvider.Instance.GetRequiredService()`.
+
+```csharp
+// Proposed in plan:
+StaticServiceProvider.Instance.GetRequiredService()
+```
+
+**Why it matters:**
+- `StaticServiceProvider.Instance` may not be initialized when obsolete constructors are called during application startup
+- Creates tight coupling to service locator pattern (anti-pattern)
+- Risk of stack overflow if resolution order is wrong
+- Hard to debug initialization failures
+
+**Required Fix:** Use `Lazy` to defer resolution:
+
+```csharp
+// In ContentService field declarations:
+private readonly Lazy _crudServiceLazy;
+
+// In obsolete constructor chain, pass a lazy resolver:
+_crudServiceLazy = new Lazy(() =>
+ StaticServiceProvider.Instance.GetRequiredService());
+
+// Usage in delegating methods:
+private IContentCrudService CrudService => _crudServiceLazy.Value;
+
+public IContent? GetById(int id) => CrudService.GetById(id);
+```
+
+Alternatively, for the primary constructor:
+
+```csharp
+// Primary constructor receives the service directly:
+public ContentService(
+ // ... other params ...
+ IContentCrudService crudService) // Direct injection
+{
+ _crudService = crudService ?? throw new ArgumentNullException(nameof(crudService));
+}
+
+// Obsolete constructors use Lazy pattern for backward compatibility
+```
+
+---
+
+### 2.3 Bug in Batch Save Audit Message
+
+**Location:** `ContentCrudService.cs` line 737
+
+**Description:**
+```csharp
+string contentIds = string.Join(", ", contentsA.Select(x => x.Id));
+Audit(AuditType.Save, userId, Constants.System.Root, $"Saved multiple content items (#{contentIds.Length})");
+```
+
+`contentIds` is a string, so `contentIds.Length` returns the **character count of the joined string**, not the **number of items**.
+
+**Example:** Saving items with IDs 1, 2, 100 produces `contentIds = "1, 2, 100"` (length 10), resulting in audit message "Saved multiple content items (#10)" instead of "#3".
+
+**Why it matters:** Audit trail will show incorrect counts, making debugging and compliance auditing unreliable.
+
+**Required Fix:**
+```csharp
+string contentIds = string.Join(", ", contentsA.Select(x => x.Id));
+Audit(AuditType.Save, userId, Constants.System.Root, $"Saved multiple content items ({contentsA.Length})");
+```
+
+Note: This bug exists in the original `ContentService.cs` at line 1202. The refactoring should fix it rather than propagate it.
+
+---
+
+### 2.4 Create Method Null Parent Error Propagation
+
+**Location:** `ContentCrudService.cs` lines 433-437 and 464-477
+
+**Description:** `Create(name, Guid parentId, ...)` calls `GetById(parentId)` which may return null, then passes null to `Create(name, IContent? parent, ...)` which throws `ArgumentNullException(nameof(parent))`.
+
+```csharp
+public IContent Create(string name, Guid parentId, string contentTypeAlias, int userId = ...)
+{
+ IContent? parent = GetById(parentId); // May return null
+ return Create(name, parent, contentTypeAlias, userId); // Throws ArgumentNullException("parent")
+}
+
+public IContent Create(string name, IContent? parent, string contentTypeAlias, int userId = ...)
+{
+ if (parent == null)
+ {
+ throw new ArgumentNullException(nameof(parent)); // Misleading error message
+ }
+ // ...
+}
+```
+
+**Why it matters:** Error message is misleading - user gets "parent cannot be null" instead of "No content with that key exists." This makes debugging harder for API consumers.
+
+**Required Fix:**
+```csharp
+public IContent Create(string name, Guid parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId)
+{
+ IContent? parent = GetById(parentId);
+ if (parent == null)
+ {
+ throw new ArgumentException($"No content with key '{parentId}' exists.", nameof(parentId));
+ }
+ return Create(name, parent, contentTypeAlias, userId);
+}
+```
+
+---
+
+### 2.5 Missing Validation in CreateAndSave with Parent Object
+
+**Location:** `ContentCrudService.cs` lines 507-529
+
+**Description:** `CreateAndSave(string name, IContent parent, ...)` calls `GetContentType(contentTypeAlias)` inside the scope, but doesn't verify the parent is not trashed before creating child content.
+
+```csharp
+public IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = ...)
+{
+ if (parent == null)
+ {
+ throw new ArgumentNullException(nameof(parent));
+ }
+
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ scope.WriteLock(Constants.Locks.ContentTree);
+ // Missing: parent.Trashed check
+
+ IContentType contentType = GetContentType(contentTypeAlias) ?? throw ...;
+ var content = new Content(name, parent, contentType, userId);
+ Save(content, userId);
+ // ...
+ }
+}
+```
+
+**Why it matters:** Users can inadvertently create content under trashed parents, which violates business rules and creates orphaned content in the recycle bin.
+
+**Required Fix:** Add validation after the write lock:
+```csharp
+using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+{
+ scope.WriteLock(Constants.Locks.ContentTree);
+
+ if (parent.Trashed)
+ {
+ throw new InvalidOperationException($"Cannot create content under trashed parent '{parent.Name}' (id={parent.Id}).");
+ }
+
+ IContentType contentType = GetContentType(contentTypeAlias)
+ ?? throw new ArgumentException("No content type with that alias.", nameof(contentTypeAlias));
+ // ...
+}
+```
+
+---
+
+### 2.6 Interface Missing Key Read Operations
+
+**Location:** `IContentCrudService.cs` - Read region
+
+**Description:** `IContentCrudService` is missing several "Get" methods that are commonly grouped with CRUD:
+- `GetAncestors(int id)` / `GetAncestors(IContent content)`
+- `GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, ...)`
+- `GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, ...)`
+
+**Why it matters:**
+- Consumers expecting a complete CRUD service will find incomplete functionality
+- Future phases will need to extend the interface, causing breaking changes
+- Tree traversal operations are fundamental to content CRUD
+
+**Required Fix:** Add these methods to `IContentCrudService`:
+
+```csharp
+#region Read (Additional)
+
+///
+/// Gets ancestors of a document.
+///
+/// Id of the document.
+/// The ancestor documents, from parent to root.
+IEnumerable GetAncestors(int id);
+
+///
+/// Gets ancestors of a document.
+///
+/// The document.
+/// The ancestor documents, from parent to root.
+IEnumerable GetAncestors(IContent content);
+
+///
+/// Gets paged children of a document.
+///
+/// Id of the parent document.
+/// Zero-based page index.
+/// Page size.
+/// Total number of children.
+/// Optional filter query.
+/// Optional ordering.
+/// The child documents.
+IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, IQuery? filter = null, Ordering? ordering = null);
+
+///
+/// Gets paged descendants of a document.
+///
+/// Id of the ancestor document.
+/// Zero-based page index.
+/// Page size.
+/// Total number of descendants.
+/// Optional filter query.
+/// Optional ordering.
+/// The descendant documents.
+IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, IQuery? filter = null, Ordering? ordering = null);
+
+#endregion
+```
+
+And implement them in `ContentCrudService` by moving the existing implementations from `ContentService`.
+
+---
+
+## 3. Minor Issues & Improvements
+
+### 3.1 Inconsistent Null Check Style
+
+**Location:** Throughout `ContentCrudService.cs`
+
+**Issue:** Mix of `is null` and `== null` patterns:
+```csharp
+if (contentType is null) // Line 449
+if (parent == null) // Line 454
+```
+
+**Recommendation:** Standardize on `is null` (C# 9+ pattern matching) for consistency with modern C# idioms.
+
+---
+
+### 3.2 Magic Number for Page Size
+
+**Location:** `ContentCrudService.cs` line 792
+
+```csharp
+const int pageSize = 500; // In DeleteLocked
+```
+
+**Recommendation:** Extract to a constant in a shared location:
+```csharp
+// In Constants.cs or a new ContentServiceConstants class
+public static class ContentServiceConstants
+{
+ public const int DefaultBatchPageSize = 500;
+}
+```
+
+---
+
+### 3.3 Memory Allocation in GetByIds
+
+**Location:** `ContentCrudService.cs` lines 557, 576
+
+```csharp
+var idsA = ids.ToArray();
+```
+
+**Issue:** This allocates an array even if the input is already an array.
+
+**Recommendation:** Use pattern matching to avoid unnecessary allocation:
+```csharp
+var idsA = ids as int[] ?? ids.ToArray();
+```
+
+---
+
+### 3.4 GetLanguageDetailsForAuditEntry Efficiency
+
+**Location:** `ContentCrudService.cs` lines 847-856
+
+```csharp
+private string GetLanguageDetailsForAuditEntry(IEnumerable affectedCultures)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
+ {
+ var languages = _languageRepository.GetMany(); // Gets ALL languages
+ // ...
+ }
+}
+```
+
+**Issue:** Retrieves ALL languages to filter for just the affected cultures. For sites with many languages, this is inefficient.
+
+**Recommendation:** Consider caching the language list at service level or filtering in the repository query.
+
+---
+
+### 3.5 Unit Test Coverage Too Minimal
+
+**Location:** `ContentCrudServiceTests.cs` in the plan
+
+**Issue:** The unit test only verifies constructor injection:
+```csharp
+[Test]
+public void Constructor_WithValidDependencies_CreatesInstance()
+{
+ // Only tests that service can be constructed
+}
+```
+
+**Recommendation:** Add at minimum:
+- Test for each `Create` overload returning non-null
+- Test for `GetById` with non-existent ID returning null
+- Test for `Save` triggering notifications (mock verification)
+- Test for `Delete` triggering cascade deletion notifications
+
+---
+
+### 3.6 Missing Using Statements
+
+**Location:** `ContentCrudService.cs` implementation
+
+**Issue:** The implementation references types without showing all required using statements:
+- `TreeChangeTypes` requires `using Umbraco.Cms.Core.Services.Changes;`
+- `Ordering` requires `using Umbraco.Cms.Core.Persistence.Querying;`
+- `TextColumnType` requires appropriate using
+
+**Recommendation:** Ensure the implementation file includes all necessary using statements.
+
+---
+
+## 4. Questions for Clarification
+
+1. **Scope Nesting Intentionality:** Is the nested scope pattern in `Delete` → `GetPagedDescendants` intentional for re-entrance support, or should the private helper assume an existing scope?
+
+2. **Interface Versioning Strategy:** Will `IContentCrudService` follow semantic versioning? Adding methods later is a breaking change for implementers.
+
+3. **Obsolete Constructor Support Duration:** The plan chains obsolete constructors to resolve IContentCrudService. How long will these be supported? Should they instead throw immediately?
+
+4. **Integration Test Selection:** The plan runs all `ContentService` tests, but doesn't specify if there are specific tests for the methods being extracted. Are there isolated tests for Create/GetById/Save/Delete that should pass first?
+
+---
+
+## 5. Summary of Required Changes
+
+| Priority | Issue | Fix |
+|----------|-------|-----|
+| **High** | 2.1 Nested scope in DeleteLocked | Refactor `GetPagedDescendants` to `GetPagedDescendantsLocked` without scope |
+| **High** | 2.2 Circular DI dependency | Use `Lazy` for obsolete constructors |
+| **High** | 2.3 Batch Save audit bug | Change `contentIds.Length` to `contentsA.Length` |
+| **Medium** | 2.4 Misleading null parent error | Add explicit check in `Create(Guid parentId, ...)` |
+| **Medium** | 2.5 Missing trashed parent check | Add `parent.Trashed` validation in `CreateAndSave` |
+| **Medium** | 2.6 Incomplete interface | Add `GetAncestors`, `GetPagedChildren`, `GetPagedDescendants` |
+| **Low** | 3.1 Inconsistent null checks | Standardize on `is null` pattern |
+| **Low** | 3.2 Magic number | Extract `pageSize = 500` to constant |
+| **Low** | 3.3 Array allocation | Use pattern matching in `GetByIds` |
+
+---
+
+## 6. Final Recommendation
+
+### ⚠️ **Approve with Changes**
+
+The plan demonstrates sound architectural thinking and follows established Umbraco patterns. The core design of extracting CRUD operations into a focused service is correct and aligns with the refactoring goals.
+
+However, **implementation cannot proceed** until the High priority issues are addressed:
+
+1. The nested scope issue (2.1) can cause deadlocks in production
+2. The DI circular dependency (2.2) can cause startup failures
+3. The audit bug (2.3) corrupts audit trail data
+
+Once these issues are fixed in the plan, implementation can proceed with confidence that the extracted service will maintain behavioral parity with the existing ContentService while improving code organization.
+
+---
+
+**Next Steps:**
+1. Update the plan to address all High priority issues
+2. Add the missing interface methods (2.6)
+3. Re-review the updated plan
+4. Proceed with implementation using `superpowers:executing-plans`
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-2.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-2.md
new file mode 100644
index 0000000000..ad535b4fa0
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-2.md
@@ -0,0 +1,530 @@
+# Critical Implementation Review: Phase 1 ContentService CRUD Extraction
+
+**Plan Version:** 1.2
+**Plan File:** `docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md`
+**Reviewer:** Critical Implementation Review
+**Date:** 2025-12-20
+
+---
+
+## 1. Overall Assessment
+
+**Summary:** The plan is well-structured with clear task sequencing, versioning strategy, and already incorporates fixes from a previous review (v1.1). The architecture follows established Umbraco patterns. However, several critical issues remain that must be addressed before implementation to prevent production bugs, performance degradation, and maintenance challenges.
+
+**Strengths:**
+- Clear versioning strategy with deprecation policy
+- TDD approach with failing tests first
+- Incremental commits for easy rollback
+- Good separation of concerns via delegation pattern
+- Previous review feedback already incorporated (nested scope fix, Lazy pattern, batch audit fix)
+
+**Major Concerns:**
+1. **GetAncestors has O(n) database round trips** for deeply nested content
+2. **Incomplete interface vs. IContentService parity** - missing methods will break delegation
+3. **Constructor bloat risk** - 17+ parameters creates maintenance burden
+4. **Filter parameter ignored** in GetPagedChildren/GetPagedDescendants
+5. **Race condition** in delete loop with concurrent operations
+
+---
+
+## 2. Critical Issues
+
+### 2.1 GetAncestors N+1 Query Pattern (Performance)
+
+**Location:** Lines 795-807 in ContentCrudService implementation
+
+**Description:** The `GetAncestors` implementation walks up the tree one node at a time:
+
+```csharp
+while (current is not null)
+{
+ ancestors.Add(current);
+ current = GetParent(current); // Each call = 1 database round trip
+}
+```
+
+**Impact:** For content at level 10, this triggers 10 separate database queries. Large sites with deep hierarchies will suffer severe performance degradation.
+
+**Fix:**
+```csharp
+public IEnumerable GetAncestors(IContent content)
+{
+ if (content?.Path == null || content.Level <= 1)
+ {
+ return Enumerable.Empty();
+ }
+
+ // Parse path to get ancestor IDs: "-1,123,456,789" -> [123, 456]
+ var ancestorIds = content.Path
+ .Split(',')
+ .Skip(1) // Skip root (-1)
+ .Select(int.Parse)
+ .Where(id => id != content.Id) // Exclude self
+ .ToArray();
+
+ return GetByIds(ancestorIds); // Single batch query
+}
+```
+
+**Severity:** HIGH - Performance critical for tree operations
+
+---
+
+### 2.2 Incomplete Interface Parity with IContentService
+
+**Location:** Lines 210-431 in IContentCrudService interface definition
+
+**Description:** The plan delegates these methods to `CrudService`, but `IContentCrudService` doesn't define them all. Specifically:
+- `GetPagedChildren` signature mismatch - existing ContentService has multiple overloads
+- Missing `HasChildren(int id)` which may be called internally
+- Missing `Exists(int id)` and `Exists(Guid key)` read operations
+
+**Impact:** When `ContentService` delegates to `CrudService`, it will get compilation errors if the interface lacks these methods.
+
+**Fix:** Audit all methods being delegated in Task 5 (lines 1249-1312) and ensure every signature exists in `IContentCrudService`. Add:
+```csharp
+bool HasChildren(int id);
+bool Exists(int id);
+bool Exists(Guid key);
+```
+
+**Severity:** HIGH - Build failure during implementation
+
+---
+
+### 2.3 Filter Parameter Silently Ignored in GetPagedChildren
+
+**Location:** Lines 818-825 in ContentCrudService implementation
+
+**Description:**
+```csharp
+if (filter is not null)
+{
+ // Note: Query combination logic would need to be implemented
+ // For now, the filter is applied after the parent filter
+}
+```
+
+The comment says "would need to be implemented" but the code doesn't implement it. The filter is passed to `DocumentRepository.GetPage` but the parent query is separate, meaning **the filter may not work correctly**.
+
+**Impact:** Callers relying on filter behavior will get unexpected results.
+
+**Fix:** Properly combine queries using the repository's query capabilities. The `DocumentRepository.GetPage` method accepts both a base query and a filter parameter, which it combines internally:
+
+```csharp
+///
+public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, IQuery? filter = null, Ordering? ordering = null)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
+ {
+ scope.ReadLock(Constants.Locks.ContentTree);
+
+ // Create base query for parent constraint
+ IQuery query = Query().Where(x => x.ParentId == id);
+
+ // Pass both query and filter to repository - repository handles combination
+ // The filter parameter is applied as an additional WHERE clause by the repository
+ return DocumentRepository.GetPage(query, pageIndex, pageSize, out totalChildren, filter, ordering);
+ }
+}
+```
+
+Remove the misleading comment block entirely. The repository's `GetPage` signature is:
+```csharp
+IEnumerable GetPage(IQuery? query, long pageIndex, int pageSize,
+ out long totalRecords, IQuery? filter, Ordering? ordering);
+```
+
+The `query` parameter provides the base constraint (parentId), and `filter` provides additional caller-specified filtering. Both are combined by the repository layer.
+
+**Severity:** HIGH - Behavioral parity violation
+
+---
+
+### 2.4 Race Condition in Delete Loop
+
+**Location:** Lines 1020-1034 in DeleteLocked
+
+**Description:**
+```csharp
+while (total > 0)
+{
+ IEnumerable descendants = GetPagedDescendantsLocked(content.Id, 0, pageSize, out total);
+ foreach (IContent c in descendants)
+ {
+ DoDelete(c);
+ }
+}
+```
+
+If another process adds content while this loop runs, `total` might never reach 0 (content added between deletion batches). Though unlikely in practice due to write locks, the loop condition is fragile.
+
+**Impact:** Potential infinite loop in rare concurrent scenarios.
+
+**Fix:** Use a bounded iteration count or break when no results returned:
+```csharp
+const int maxIterations = 10000; // Safety limit
+int iterations = 0;
+while (total > 0 && iterations++ < maxIterations)
+{
+ IEnumerable descendants = GetPagedDescendantsLocked(content.Id, 0, pageSize, out total);
+ var batch = descendants.ToList(); // Materialize once
+ if (batch.Count == 0) break; // No more results, exit even if total > 0
+
+ foreach (IContent c in batch)
+ {
+ DoDelete(c);
+ }
+}
+
+if (iterations >= maxIterations)
+{
+ _logger.LogWarning("Delete operation for content {ContentId} reached max iterations ({MaxIterations})",
+ content.Id, maxIterations);
+}
+```
+
+**Severity:** MEDIUM - Edge case but could cause production issues
+
+---
+
+### 2.5 Missing Logging for Operation Failures
+
+**Location:** Throughout ContentCrudService implementation
+
+**Description:** The `Save` and `Delete` methods don't log when operations are cancelled or fail. The original `ContentService` has `_logger` usage in critical paths.
+
+**Impact:** Production debugging becomes difficult without visibility into cancelled operations.
+
+**Fix:** Add logging for cancellation and validation failures:
+```csharp
+if (scope.Notifications.PublishCancelable(savingNotification))
+{
+ _logger.LogInformation("Save operation cancelled for content {ContentId} by notification handler", content.Id);
+ scope.Complete();
+ return OperationResult.Cancel(eventMessages);
+}
+```
+
+**Severity:** MEDIUM - Operational visibility
+
+---
+
+### 2.6 ContentServiceBase Audit Method Blocks Async
+
+**Location:** Lines 133-135 in ContentServiceBase
+
+**Description:**
+```csharp
+protected void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null) =>
+ AuditAsync(type, userId, objectId, message, parameters).GetAwaiter().GetResult();
+```
+
+Using `.GetAwaiter().GetResult()` blocks the thread and can cause deadlocks in certain synchronization contexts.
+
+**Impact:** Potential deadlocks on ASP.NET Core when called from async context.
+
+**Note:** This matches the existing `ContentService` pattern (line 3122-3123), so maintaining parity is acceptable for Phase 1. However, consider marking this for future refactoring to async-first approach.
+
+**Severity:** LOW (maintains existing behavior) - Flag for future phases
+
+---
+
+## 3. Minor Issues & Improvements
+
+### 3.1 Inconsistent Null-Forgiving Operator Usage
+
+**Location:** Line 643 - `new Content(name, parent!, contentType, userId)`
+
+**Issue:** Uses `!` on parent despite checking `parentId > 0 && parent is null` throws. This is correct but looks suspicious.
+
+**Suggestion:** Add comment or restructure:
+```csharp
+// Parent is guaranteed non-null here because parentId > 0 and we throw if parent not found
+Content content = new Content(name, parent!, contentType, userId);
+```
+
+### 3.2 Code Duplication in CreateAndSave Overloads
+
+**Location:** Lines 620-683 (both CreateAndSave methods)
+
+**Issue:** Both methods have nearly identical validation and setup logic.
+
+**Suggestion:** Extract common logic to private helper:
+```csharp
+private Content CreateContentInternal(string name, IContent? parent, int parentId, IContentType contentType, int userId)
+{
+ // Shared validation and construction
+}
+```
+
+### 3.3 Missing XML Documentation for Internal Methods
+
+**Location:** `GetPagedDescendantsLocked`, `DeleteLocked`
+
+**Issue:** Internal methods lack documentation about preconditions (must be called within scope with write lock).
+
+**Suggestion:** Add `` documenting the scope/lock requirements.
+
+### 3.4 Test Coverage Gap
+
+**Location:** Task 3, Step 1 - Only one unit test
+
+**Issue:** The single constructor test (`Constructor_WithValidDependencies_CreatesInstance`) doesn't test any actual behavior.
+
+**Suggestion:** Add unit tests for:
+- `Create` with invalid parent ID throws
+- `Create` with null content type throws
+- `GetById` returns null for non-existent ID
+- Batch save with empty collection
+
+### 3.5 Potential Memory Pressure in GetByIds Dictionary
+
+**Location:** Lines 723-724
+
+```csharp
+var index = items.ToDictionary(x => x.Id, x => x);
+return idsA.Select(x => index.GetValueOrDefault(x)).WhereNotNull();
+```
+
+**Issue:** For large ID arrays, creating a dictionary doubles memory.
+
+**Suggestion:** Only optimize if profiling shows issues. Current approach is correct for most use cases.
+
+---
+
+## 4. Questions for Clarification
+
+1. **Circular Dependency Verification:** Has the `Lazy` pattern in obsolete constructors been verified to work at runtime? The plan mentions the risk but doesn't confirm testing.
+
+2. **ContentSchedule Handling:** The `Save` method accepts `ContentScheduleCollection` but the batch save doesn't. Is this intentional parity with existing behavior?
+
+3. **Tree Traversal Methods:** The plan adds `GetAncestors`, `GetPagedChildren`, `GetPagedDescendants` to the CRUD service. Are these truly CRUD operations, or should they remain in a separate "navigation" service in future phases?
+
+4. **Notification State Passing:** The `ContentSavedNotification` uses `.WithStateFrom(savingNotification)`. Is the state transfer pattern tested for the delegated implementation?
+
+---
+
+## 5. Benchmark Regression Threshold Enforcement
+
+**Question from Plan:** The plan mentions "no >20% regression" in benchmarks. Where is this threshold defined and enforced?
+
+**Recommendation:** Implement in-test assertions with specific gating for Phase 1 CRUD benchmarks.
+
+### 5.1 Implementation: Update ContentServiceBenchmarkBase
+
+Add the following to `tests/Umbraco.Tests.Integration/Testing/ContentServiceBenchmarkBase.cs`:
+
+```csharp
+// Add to class fields
+private static readonly string BaselinePath = Path.Combine(
+ TestContext.CurrentContext.TestDirectory,
+ "..", "..", "..", "..", "..",
+ "docs", "plans", "baseline-phase0.json");
+
+private Dictionary? _baseline;
+private const double DefaultRegressionThreshold = 20.0;
+
+///
+/// Records a benchmark and asserts no regression beyond the threshold.
+///
+/// Benchmark name (must match baseline JSON key).
+/// Measured elapsed time in milliseconds.
+/// Number of items processed.
+/// Maximum allowed regression percentage (default: 20%).
+protected void AssertNoRegression(string name, long elapsedMs, int itemCount, double thresholdPercent = DefaultRegressionThreshold)
+{
+ RecordBenchmark(name, elapsedMs, itemCount);
+
+ _baseline ??= LoadBaseline();
+
+ if (_baseline.TryGetValue(name, out var baselineResult))
+ {
+ var maxAllowed = baselineResult.ElapsedMs * (1 + thresholdPercent / 100);
+
+ if (elapsedMs > maxAllowed)
+ {
+ var regressionPct = ((double)(elapsedMs - baselineResult.ElapsedMs) / baselineResult.ElapsedMs) * 100;
+ Assert.Fail(
+ $"Performance regression detected for '{name}': " +
+ $"{elapsedMs}ms exceeds threshold of {maxAllowed:F0}ms " +
+ $"(baseline: {baselineResult.ElapsedMs}ms, regression: +{regressionPct:F1}%, threshold: {thresholdPercent}%)");
+ }
+
+ TestContext.WriteLine($"[REGRESSION_CHECK] {name}: PASS ({elapsedMs}ms <= {maxAllowed:F0}ms, baseline: {baselineResult.ElapsedMs}ms)");
+ }
+ else
+ {
+ TestContext.WriteLine($"[REGRESSION_CHECK] {name}: SKIPPED (no baseline entry)");
+ }
+}
+
+///
+/// Measures, records, and asserts no regression for the given action.
+///
+protected long MeasureAndAssertNoRegression(string name, int itemCount, Action action, bool skipWarmup = false, double thresholdPercent = DefaultRegressionThreshold)
+{
+ // Warmup iteration (skip for destructive operations)
+ if (!skipWarmup)
+ {
+ try { action(); }
+ catch { /* Warmup failure acceptable */ }
+ }
+
+ var sw = Stopwatch.StartNew();
+ action();
+ sw.Stop();
+
+ AssertNoRegression(name, sw.ElapsedMilliseconds, itemCount, thresholdPercent);
+ return sw.ElapsedMilliseconds;
+}
+
+private Dictionary LoadBaseline()
+{
+ if (!File.Exists(BaselinePath))
+ {
+ TestContext.WriteLine($"[BASELINE] File not found: {BaselinePath}");
+ return new Dictionary();
+ }
+
+ try
+ {
+ var json = File.ReadAllText(BaselinePath);
+ var results = JsonSerializer.Deserialize>(json) ?? new List();
+ TestContext.WriteLine($"[BASELINE] Loaded {results.Count} baseline entries from {BaselinePath}");
+ return results.ToDictionary(r => r.Name, r => r);
+ }
+ catch (Exception ex)
+ {
+ TestContext.WriteLine($"[BASELINE] Failed to load baseline: {ex.Message}");
+ return new Dictionary();
+ }
+}
+```
+
+### 5.2 Phase 1 CRUD Benchmarks to Gate
+
+Update `ContentServiceRefactoringBenchmarks.cs` to use `AssertNoRegression` for these Phase 1 CRUD operations:
+
+| Benchmark | Gate? | Baseline (ms) | Max Allowed (ms) |
+|-----------|-------|---------------|------------------|
+| `Save_SingleItem` | ✅ Yes | 7 | 8.4 |
+| `Save_BatchOf100` | ✅ Yes | 676 | 811.2 |
+| `Save_BatchOf1000` | ✅ Yes | 7649 | 9178.8 |
+| `GetById_Single` | ✅ Yes | 8 | 9.6 |
+| `GetByIds_BatchOf100` | ✅ Yes | 14 | 16.8 |
+| `Delete_SingleItem` | ✅ Yes | 35 | 42 |
+| `Delete_WithDescendants` | ✅ Yes | 243 | 291.6 |
+| `GetAncestors_DeepHierarchy` | ✅ Yes | 31 | 37.2 |
+| `GetPagedChildren_100Items` | ✅ Yes | 16 | 19.2 |
+| `GetPagedDescendants_DeepTree` | ✅ Yes | 25 | 30 |
+
+**Non-gated (Phase 2+):** `Publish_*`, `Move_*`, `Copy_*`, `Sort_*`, `EmptyRecycleBin_*`, `Rollback_*`, `*Versions*`
+
+### 5.3 Example Updated Benchmark Test
+
+```csharp
+///
+/// Benchmark 1: Single content save latency.
+///
+[Test]
+[LongRunning]
+public void Benchmark_Save_SingleItem()
+{
+ // Warmup with throwaway content
+ var warmupContent = ContentBuilder.CreateSimpleContent(ContentType, "Warmup_SingleItem", -1);
+ ContentService.Save(warmupContent);
+
+ // Measured run with fresh content
+ var content = ContentBuilder.CreateSimpleContent(ContentType, "BenchmarkSingle", -1);
+ var sw = Stopwatch.StartNew();
+ ContentService.Save(content);
+ sw.Stop();
+
+ // Gate: Fail if >20% regression from baseline
+ AssertNoRegression("Save_SingleItem", sw.ElapsedMilliseconds, 1);
+
+ Assert.That(content.Id, Is.GreaterThan(0));
+}
+```
+
+### 5.4 Baseline Update Process
+
+When a phase completes and performance characteristics change intentionally:
+
+```bash
+# 1. Run benchmarks and capture new results
+dotnet test tests/Umbraco.Tests.Integration \
+ --filter "Category=Benchmark&FullyQualifiedName~ContentServiceRefactoringBenchmarks" \
+ --logger "console;verbosity=detailed" \
+ | tee benchmark-output.txt
+
+# 2. Extract JSON from output
+grep -oP '\[BENCHMARK_JSON\]\K.*(?=\[/BENCHMARK_JSON\])' benchmark-output.txt \
+ | python3 -m json.tool > docs/plans/baseline-phase1.json
+
+# 3. Commit with phase tag
+git add docs/plans/baseline-phase1.json
+git commit -m "chore: update benchmark baseline for Phase 1"
+git tag phase-1-baseline
+```
+
+### 5.5 Environment Variability Considerations
+
+Benchmark thresholds account for environment variability:
+- **20% threshold** provides buffer for CI vs. local differences
+- **Warmup runs** reduce JIT compilation variance
+- **Database per test** ensures isolation
+- **Non-parallelizable** attribute prevents resource contention
+
+If false positives occur in CI, consider:
+1. Increasing threshold to 30% for CI-only runs
+2. Using environment variable: `BENCHMARK_THRESHOLD=30`
+3. Running benchmarks on dedicated hardware
+
+---
+
+## 6. Final Recommendation
+
+**Recommendation:** :warning: **Approve with Changes**
+
+The plan is sound architecturally but has critical issues that must be fixed before implementation:
+
+### Required Changes (Must Fix)
+
+| Priority | Issue | Fix |
+|----------|-------|-----|
+| P0 | GetAncestors N+1 | Use batch query via Path parsing |
+| P0 | Incomplete interface parity | Audit and add missing methods (`HasChildren`, `Exists`) |
+| P0 | Filter ignored silently | Use repository query combination (pass base query + filter to `GetPage`) |
+| P0 | Benchmark regression enforcement | Implement `AssertNoRegression` in `ContentServiceBenchmarkBase` |
+| P1 | Delete loop race condition | Add iteration bound and empty-batch break |
+| P1 | Missing operation logging | Add cancellation/failure logging |
+
+### Recommended Changes (Should Fix)
+
+| Priority | Issue | Fix |
+|----------|-------|-----|
+| P2 | Code duplication in CreateAndSave | Extract to helper method |
+| P2 | Thin test coverage | Add behavioral unit tests |
+| P2 | Internal method documentation | Add precondition remarks |
+| P2 | Update CRUD benchmarks | Replace `RecordBenchmark` with `AssertNoRegression` for Phase 1 ops |
+
+### Implementation Checklist
+
+Before proceeding to implementation, ensure:
+
+- [ ] `GetAncestors` uses `Path` parsing with batch `GetByIds`
+- [ ] `IContentCrudService` includes `HasChildren(int)`, `Exists(int)`, `Exists(Guid)`
+- [ ] `GetPagedChildren`/`GetPagedDescendants` pass both `query` and `filter` to repository
+- [ ] `ContentServiceBenchmarkBase` has `AssertNoRegression` method
+- [ ] 10 Phase 1 CRUD benchmarks use `AssertNoRegression` instead of `RecordBenchmark`
+- [ ] `DeleteLocked` has iteration bound and empty-batch exit
+- [ ] Save/Delete operations log cancellations
+
+Once the P0 and P1 issues are addressed, the plan can proceed to implementation.
+
+---
+
+**Reviewed by:** Critical Implementation Review Skill
+**Review Date:** 2025-12-20
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-3.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-3.md
new file mode 100644
index 0000000000..8ab54f2e9a
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-3.md
@@ -0,0 +1,626 @@
+# Critical Implementation Review #3: Phase 1 ContentService CRUD Extraction
+
+**Plan Version Reviewed:** 1.3 (2025-12-20)
+**Review Date:** 2025-12-20
+**Reviewer:** Claude (Senior Staff Engineer)
+**Plan File:** `docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md`
+
+---
+
+## 1. Overall Assessment
+
+**Strengths:**
+- Well-structured TDD approach with clear task breakdown
+- Versioning strategy is thoughtfully documented
+- Previous critical review feedback (reviews 1 & 2) has been systematically addressed
+- N+1 query in `GetAncestors` correctly fixed with batch `Path` parsing
+- Benchmark regression enforcement adds meaningful quality gate (20% threshold)
+- Safety bounds on `DeleteLocked` iteration (10,000 max) prevent infinite loops
+- Comprehensive XML documentation with preconditions for internal methods
+
+**Major Concerns:**
+- Synchronous wrapper over async code in `ContentServiceBase.Audit` can cause deadlocks
+- Multiple nested scope creations will degrade performance
+- Versioning policy describes default interface methods but implementation uses abstract base class
+- Thread-safety issue in benchmark baseline loading
+- Lock acquisition timing allows race conditions in `Save()` validation
+
+**Verdict:** Plan is well-structured but requires targeted fixes before implementation.
+
+---
+
+## 2. Critical Issues (P0 — Must Fix Before Implementation)
+
+### 2.1 Synchronous Async Wrapper — Potential Deadlock
+
+**Location:** `ContentServiceBase.cs` lines 134-136
+
+```csharp
+protected void Audit(...) =>
+ AuditAsync(...).GetAwaiter().GetResult();
+```
+
+**Why it matters:** `.GetAwaiter().GetResult()` blocks the calling thread waiting for an async operation. While ASP.NET Core doesn't use `SynchronizationContext` by default, this pattern:
+1. Blocks a thread pool thread unnecessarily, reducing throughput under load
+2. Breaks if someone configures a `SynchronizationContext`
+3. Sets a bad precedent in a base class that will be inherited by multiple services
+4. Can cause deadlocks in certain hosting scenarios (IIS in-process, custom middleware)
+
+**Impact:** Application hangs under load; difficult to diagnose in production.
+
+**Recommended Fix:** Provide synchronous audit path that doesn't require async:
+
+```csharp
+///
+/// Records an audit entry for a content operation (synchronous).
+///
+protected void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null)
+{
+ // Resolve user key synchronously - IUserIdKeyResolver should have sync overload
+ // For now, use the async pattern with ConfigureAwait(false) to avoid context capture
+ Guid userKey = UserIdKeyResolver.GetAsync(userId).ConfigureAwait(false).GetAwaiter().GetResult();
+
+ AuditService.Add(
+ type,
+ userKey,
+ objectId,
+ UmbracoObjectTypes.Document.GetName(),
+ message,
+ parameters);
+}
+```
+
+**Alternative (Preferred Long-Term):** Add `IAuditService.Add()` synchronous overload and `IUserIdKeyResolver.Get(int userId)` synchronous overload. This avoids the async-over-sync anti-pattern entirely.
+
+**Action Required:**
+- [ ] Check if `IAuditService` has synchronous `Add` method
+- [ ] Check if `IUserIdKeyResolver` has synchronous `Get` method
+- [ ] If not, use `ConfigureAwait(false)` pattern as shown above
+- [ ] Add `// TODO: Replace with sync overloads when available` comment
+
+---
+
+### 2.2 Nested Scope Creation — Performance Degradation
+
+**Locations:**
+- `GetContentType()` creates its own scope (lines 1338-1345)
+- `GetLanguageDetailsForAuditEntry()` creates its own scope (lines 1347-1356)
+- `Create(int parentId, ...)` calls `GetById(parentId)` which creates scope, then continues without scope
+- `GetParent(int id)` calls `GetById(id)` then `GetById(content.ParentId)` — 2 scopes
+
+**Why it matters:** Each `CreateCoreScope()` call:
+- Acquires a database connection from the pool
+- Creates a new transaction context
+- Has overhead for read/write lock acquisition
+- Adds latency (~0.5-2ms per scope depending on connection pool state)
+
+**Impact:** A single `Save()` operation calling `GetLanguageDetailsForAuditEntry()` creates 2+ scopes. At baseline ~7ms per save, this overhead compounds:
+- 100 saves: +50-200ms overhead
+- 1000 saves: +500-2000ms overhead
+
+**Recommended Fix:** Create `*Locked` or `*Internal` variants that assume caller holds scope:
+
+```csharp
+// Public API - creates scope
+public IContentType GetContentType(string alias)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true))
+ {
+ scope.ReadLock(Constants.Locks.ContentTypes);
+ return GetContentTypeLocked(alias);
+ }
+}
+
+// Internal - assumes caller holds scope with appropriate lock
+private IContentType GetContentTypeLocked(string alias)
+{
+ return _contentTypeRepository.Get(alias)
+ ?? throw new ArgumentException($"No content type with alias '{alias}' exists.", nameof(alias));
+}
+
+// In Save() - reuse the scope
+public OperationResult Save(IContent content, ...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ scope.WriteLock(Constants.Locks.ContentTree);
+ // ...
+ if (culturesChanging != null)
+ {
+ // Use locked variant - no nested scope
+ var langs = GetLanguageDetailsForAuditEntryLocked(culturesChanging);
+ Audit(AuditType.SaveVariant, userId.Value, content.Id, $"Saved languages: {langs}", langs);
+ }
+ // ...
+ }
+}
+```
+
+**Files to Update:**
+- [ ] `ContentCrudService.cs`: Add `GetContentTypeLocked()`, `GetLanguageDetailsForAuditEntryLocked()`
+- [ ] Update `Save()`, `CreateAndSaveInternal()` to use locked variants
+- [ ] Document preconditions in XML comments for locked methods
+
+---
+
+### 2.3 Interface Versioning Policy — Clarify Inheritance Requirement
+
+**Location:** Versioning Strategy section (lines 28-70)
+
+**Issue:** The plan states:
+> "When adding new methods to `IContentCrudService`, provide a default implementation in `ContentServiceBase`"
+
+This conflates C# 8+ default interface methods with abstract base class implementations. The current design requires `ContentServiceBase` inheritance, which is the correct approach but needs explicit documentation.
+
+**Resolution (Agreed):** Use Option B — Document that `ContentServiceBase` inheritance is required.
+
+**Recommended Changes:**
+
+1. **Update Versioning Strategy section** — Replace lines 46-55 with:
+
+```markdown
+### Interface Extensibility Model
+
+`IContentCrudService` is designed for **composition, not direct implementation**.
+
+**Supported usage:**
+- Inject `IContentCrudService` as a dependency ✅
+- Extend `ContentCrudService` via inheritance ✅
+- Replace registration in DI with custom implementation inheriting `ContentServiceBase` ✅
+
+**Unsupported usage:**
+- Implement `IContentCrudService` directly without inheriting `ContentServiceBase` ❌
+
+**Rationale:** All CRUD operations require shared infrastructure (scoping, repositories,
+auditing). `ContentServiceBase` provides this infrastructure. Direct interface implementation
+would require re-implementing this infrastructure correctly, which is error-prone and
+creates maintenance burden.
+
+**Adding New Methods (Umbraco internal process):**
+1. Add method signature to `IContentCrudService` interface
+2. Add virtual implementation to `ContentServiceBase` (if shareable) or `ContentCrudService`
+3. Existing subclasses automatically inherit the new implementation
+4. Mark with `[Since("X.Y")]` attribute if adding after initial release
+```
+
+2. **Update IContentCrudService XML documentation** — Add implementation warning:
+
+```csharp
+///
+/// Service for content CRUD (Create, Read, Update, Delete) operations.
+///
+///
+///
+/// Implementation Note: Do not implement this interface directly.
+/// Instead, inherit from which provides required
+/// infrastructure (scoping, repository access, auditing). Direct implementation
+/// without this base class will result in missing functionality.
+///
+///
+/// This interface is part of the ContentService refactoring initiative.
+/// It extracts core CRUD operations into a focused, testable service.
+///
+/// ...
+///
+public interface IContentCrudService : IService
+```
+
+---
+
+### 2.4 Validation Before Lock — Race Condition Window
+
+**Location:** `Save()` method lines 1077-1091
+
+```csharp
+public OperationResult Save(IContent content, ...)
+{
+ PublishedState publishedState = content.PublishedState;
+ // Validation happens BEFORE lock acquisition
+ if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
+ throw new InvalidOperationException(...);
+
+ if (content.Name != null && content.Name.Length > 255)
+ throw new InvalidOperationException(...);
+
+ EventMessages eventMessages = EventMessagesFactory.Get();
+
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ // Lock acquired AFTER validation
+ scope.WriteLock(Constants.Locks.ContentTree);
+```
+
+**Why it matters:** The content object's state could theoretically change between validation and lock acquisition if:
+- Another thread modifies the same `IContent` instance
+- The object is shared across async contexts
+
+While unlikely in typical usage, this violates transactional consistency principles.
+
+**Recommended Fix:** Move validation inside the locked section:
+
+```csharp
+public OperationResult Save(IContent content, ...)
+{
+ EventMessages eventMessages = EventMessagesFactory.Get();
+
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ scope.WriteLock(Constants.Locks.ContentTree);
+
+ // Validate AFTER acquiring lock — content state is now stable
+ PublishedState publishedState = content.PublishedState;
+ if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
+ {
+ throw new InvalidOperationException(
+ $"Cannot save (un)publishing content with name: {content.Name} - and state: {content.PublishedState}");
+ }
+
+ if (content.Name != null && content.Name.Length > 255)
+ {
+ throw new InvalidOperationException(
+ $"Content with the name {content.Name} cannot be more than 255 characters in length.");
+ }
+
+ // Continue with save...
+```
+
+**Trade-off:** Lock is held slightly longer during validation. However, validation is O(1) string length check, so impact is negligible (~microseconds).
+
+---
+
+## 3. High Priority Issues (P1 — Should Fix)
+
+### 3.1 Thread-Unsafe Baseline Loading in Benchmarks
+
+**Location:** `ContentServiceBenchmarkBase.cs` lines 1688-1689
+
+```csharp
+private Dictionary? _baseline;
+
+protected void AssertNoRegression(...)
+{
+ _baseline ??= LoadBaseline(); // Race condition if tests run in parallel
+```
+
+**Why it matters:** NUnit can run tests in parallel (default behavior). Multiple threads checking `_baseline == null` simultaneously could:
+- Both see `null` and both call `LoadBaseline()`
+- Cause file I/O contention
+- Result in `JsonSerializer` errors if file is read concurrently
+- Produce inconsistent baseline state
+
+**Recommended Fix:** Use `Lazy` for thread-safe initialization:
+
+```csharp
+private static readonly Lazy> _baselineLoader =
+ new(() => LoadBaselineInternal(), LazyThreadSafetyMode.ExecutionAndPublication);
+
+private static Dictionary Baseline => _baselineLoader.Value;
+
+protected void AssertNoRegression(string name, long elapsedMs, int itemCount, double thresholdPercent = DefaultRegressionThreshold)
+{
+ RecordBenchmark(name, elapsedMs, itemCount);
+
+ if (Baseline.TryGetValue(name, out var baselineResult))
+ {
+ // ... regression check logic
+ }
+}
+
+private static Dictionary LoadBaselineInternal()
+{
+ // ... existing LoadBaseline logic, but static
+}
+```
+
+---
+
+### 3.2 Baseline Path Uses Relative Navigation — Brittle
+
+**Location:** `ContentServiceBenchmarkBase.cs` lines 1670-1673
+
+```csharp
+private static readonly string BaselinePath = Path.Combine(
+ TestContext.CurrentContext.TestDirectory,
+ "..", "..", "..", "..", "..",
+ "docs", "plans", "baseline-phase0.json");
+```
+
+**Why it matters:** `TestContext.CurrentContext.TestDirectory` varies by:
+- Test runner (Visual Studio, Rider, dotnet CLI, NCrunch)
+- Build configuration (Debug/Release)
+- CI/CD environment (GitHub Actions, Azure DevOps)
+
+Five `..` navigations are fragile and will break when project structure changes.
+
+**Recommended Fix:** Use repository root detection:
+
+```csharp
+private static string FindRepositoryRoot()
+{
+ var dir = new DirectoryInfo(TestContext.CurrentContext.TestDirectory);
+ while (dir != null)
+ {
+ if (File.Exists(Path.Combine(dir.FullName, "umbraco.sln")))
+ {
+ return dir.FullName;
+ }
+ dir = dir.Parent;
+ }
+ throw new InvalidOperationException(
+ $"Cannot find repository root (umbraco.sln) starting from {TestContext.CurrentContext.TestDirectory}");
+}
+
+private static readonly Lazy _repositoryRoot = new(FindRepositoryRoot);
+
+private static string BaselinePath => Path.Combine(_repositoryRoot.Value, "docs", "plans", "baseline-phase0.json");
+```
+
+---
+
+### 3.3 GetByIds Dictionary Key Collision Risk
+
+**Location:** `ContentCrudService.cs` lines 909-910
+
+```csharp
+var index = items.ToDictionary(x => x.Id, x => x);
+```
+
+**Why it matters:** If `DocumentRepository.GetMany()` returns duplicates (due to repository bug, database inconsistency, or future ORM change), `.ToDictionary()` throws `ArgumentException: An item with the same key has already been added`.
+
+**Impact:** Service method crashes with unhelpful exception instead of gracefully handling data inconsistency.
+
+**Recommended Fix:** Use safe dictionary construction:
+
+```csharp
+// Option 1: Take first occurrence (matches current behavior intent)
+var index = items.GroupBy(x => x.Id).ToDictionary(g => g.Key, g => g.First());
+
+// Option 2: Use TryAdd pattern (more explicit)
+var index = new Dictionary();
+foreach (var item in items)
+{
+ index.TryAdd(item.Id, item); // Silently ignores duplicates
+}
+```
+
+Apply same fix to `GetByIds(IEnumerable)` (line 931).
+
+---
+
+### 3.4 Missing ContentSchedule Support in Batch Save
+
+**Location:** `IContentCrudService.cs` lines 436-438
+
+```csharp
+OperationResult Save(IEnumerable contents, int userId = Constants.Security.SuperUserId);
+```
+
+The batch `Save` doesn't accept `ContentScheduleCollection`, but the single-item `Save` does:
+
+```csharp
+OperationResult Save(IContent content, int? userId = null, ContentScheduleCollection? contentSchedule = null);
+```
+
+**Why it matters:** Users needing to save multiple items with individual schedules must:
+1. Make N individual `Save()` calls (defeats batching purpose)
+2. Or call batch `Save()` then separately persist schedules (inconsistent transaction)
+
+**Recommended Fix (Documentation):** Add XML doc noting the limitation:
+
+```csharp
+///
+/// Saves multiple documents.
+///
+/// The documents to save.
+/// Optional id of the user saving the content.
+/// The operation result.
+///
+/// This method does not support content schedules. To save content with schedules,
+/// use the single-item overload.
+///
+OperationResult Save(IEnumerable contents, int userId = Constants.Security.SuperUserId);
+```
+
+**Future Enhancement (Optional):** Consider adding:
+```csharp
+OperationResult Save(IEnumerable<(IContent Content, ContentScheduleCollection? Schedule)> items, int userId = ...);
+```
+
+---
+
+## 4. Medium Priority Issues (P2 — Recommended)
+
+### 4.1 Unit Test Mock Setup Repetition
+
+**Location:** `ContentCrudServiceTests.cs` lines 570-579 (repeated 6+ times)
+
+Each test repeats the same ~10-line `CreateCoreScope` mock setup.
+
+**Recommendation:** Extract to helper:
+
+```csharp
+private ICoreScope CreateMockScopeWithReadLock()
+{
+ var scope = new Mock();
+ scope.Setup(x => x.ReadLock(It.IsAny()));
+ _scopeProvider.Setup(x => x.CreateCoreScope(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()))
+ .Returns(scope.Object);
+ return scope.Object;
+}
+
+private ICoreScope CreateMockScopeWithWriteLock()
+{
+ var scope = CreateMockScopeWithReadLock();
+ Mock.Get(scope).Setup(x => x.WriteLock(It.IsAny()));
+ Mock.Get(scope).Setup(x => x.Notifications).Returns(Mock.Of());
+ return scope;
+}
+```
+
+---
+
+### 4.2 Benchmark Threshold Should Be Configurable
+
+**Location:** `ContentServiceBenchmarkBase.cs` line 1683
+
+```csharp
+private const double DefaultRegressionThreshold = 20.0;
+```
+
+**Recommendation:** Allow CI override via environment variable:
+
+```csharp
+private static readonly double RegressionThreshold =
+ double.TryParse(Environment.GetEnvironmentVariable("BENCHMARK_REGRESSION_THRESHOLD"), out var t)
+ ? t
+ : 20.0;
+```
+
+This allows tightening thresholds in CI while keeping development lenient.
+
+---
+
+### 4.3 Missing Test Category Attributes
+
+**Location:** `ContentCrudServiceTests.cs`
+
+The unit tests lack `[Category("UnitTest")]` attribute, making it harder to filter:
+
+```bash
+# Can't easily run only unit tests
+dotnet test --filter "Category=UnitTest"
+```
+
+**Recommendation:** Add category:
+
+```csharp
+[TestFixture]
+[Category("UnitTest")]
+public class ContentCrudServiceTests
+```
+
+---
+
+### 4.4 Summary Table File Count Mismatch
+
+**Location:** Task 7 Summary (line 1916)
+
+The table states "4 new files" but Task 2 creates `IContentCrudService.cs` as a 5th file.
+
+**Files created:**
+1. `ContentServiceBase.cs`
+2. `ContentServiceConstants.cs`
+3. `IContentCrudService.cs`
+4. `ContentCrudService.cs`
+5. `ContentCrudServiceTests.cs`
+
+**Fix:** Update summary to "5 new files".
+
+---
+
+### 4.5 GetAncestors Return Order Inconsistency
+
+**Location:** `ContentCrudService.cs` lines 988-998
+
+**Documentation says:**
+> Returns: The ancestor documents, from parent to root.
+
+**Implementation does:**
+```csharp
+var ancestorIds = content.Path
+ .Split(',')
+ .Skip(1) // Skip root (-1)
+ .Select(int.Parse)
+ .Where(id => id != content.Id)
+ .ToArray();
+
+return GetByIds(ancestorIds); // Returns in path order: root -> parent
+```
+
+Path format is `-1,123,456,789` where 123 is closest to root, 789 is the item.
+After `Skip(1)` and excluding self: `[123, 456]` — this is root-to-parent order.
+
+**Recommendation:** Either:
+1. Fix documentation: "from root to parent"
+2. Or reverse the array: `ancestorIds.Reverse().ToArray()`
+
+Check existing `ContentService.GetAncestors` behavior for consistency.
+
+---
+
+## 5. Questions for Clarification
+
+| # | Question | Impact |
+|---|----------|--------|
+| 1 | Is there an async version of this interface planned? Many services in codebase have `*Async` variants. | Affects whether to add async methods now or later |
+| 2 | What should happen if `baseline-phase0.json` is missing in CI? Current: skip silently. Alternative: fail hard. | Affects CI reliability |
+| 3 | `GetPagedDescendantsLocked` is private but mentioned in interface method count (24 total). Should it be internal/protected? | Documentation accuracy |
+| 4 | Does `IUserIdKeyResolver` have a synchronous `Get` method, or only `GetAsync`? | Affects 2.1 fix approach |
+
+---
+
+## 6. Implementation Checklist Update
+
+Add these items to the existing checklist in the plan:
+
+```markdown
+### Critical Review 3 Changes Required
+
+**P0 - Must Fix:**
+- [ ] Fix `Audit()` async wrapper (use `ConfigureAwait(false)` or sync overloads)
+- [ ] Add `*Locked` variants for `GetContentType`, `GetLanguageDetailsForAuditEntry`
+- [ ] Update Versioning Strategy to document `ContentServiceBase` inheritance requirement
+- [ ] Add implementation warning to `IContentCrudService` XML docs
+- [ ] Move `Save()` validation inside locked section
+
+**P1 - Should Fix:**
+- [ ] Make baseline loading thread-safe with `Lazy`
+- [ ] Use repository root detection for baseline path
+- [ ] Handle duplicate keys in `GetByIds` dictionary construction
+- [ ] Add XML doc to batch `Save` noting schedule limitation
+
+**P2 - Recommended:**
+- [ ] Extract mock setup helpers in unit tests
+- [ ] Add `[Category("UnitTest")]` to test fixture
+- [ ] Update summary table to "5 new files"
+- [ ] Verify/fix `GetAncestors` return order documentation
+- [ ] Make regression threshold configurable via environment variable
+```
+
+---
+
+## 7. Final Recommendation
+
+**Approve with Changes**
+
+The plan is well-structured and has comprehensively addressed feedback from reviews 1 and 2. The identified issues are targeted and fixable without architectural changes.
+
+### Priority Summary
+
+| Priority | Count | Effort Estimate |
+|----------|-------|-----------------|
+| P0 (Must Fix) | 4 | ~2-3 hours |
+| P1 (Should Fix) | 4 | ~1-2 hours |
+| P2 (Recommended) | 5 | ~30 min |
+
+### Before Implementation:
+1. Apply all P0 fixes to the plan
+2. Apply P1 fixes (strongly recommended)
+3. P2 can be addressed during implementation
+
+### Sign-off Criteria:
+- [ ] All P0 items resolved in plan v1.4
+- [ ] P1 items either resolved or documented as known limitations
+- [ ] Plan version incremented with "Critical Review 3 Changes Applied" section
+
+---
+
+**Review Complete:** 2025-12-20
+**Next Action:** Update plan to v1.4 with fixes, then proceed to implementation
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-4.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-4.md
new file mode 100644
index 0000000000..569d4e6f38
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-4.md
@@ -0,0 +1,558 @@
+# Critical Implementation Review: Phase 1 ContentService CRUD Extraction
+
+**Plan Document:** `docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md`
+**Plan Version:** 1.4
+**Reviewer:** Claude (Senior Staff Engineer)
+**Review Date:** 2025-12-20
+**Review Type:** Detailed Implementation Review (Pre-Implementation Gate)
+
+---
+
+## 1. Overall Assessment
+
+This is a well-structured plan that has incorporated feedback from three prior critical reviews. The versioning strategy, interface design, and test coverage are thorough. The TDD approach with explicit test-first steps is commendable.
+
+### Strengths
+
+- **Comprehensive versioning policy** with clear 2-major-version deprecation timeline
+- **N+1 query fix** for `GetAncestors` using batch fetch with path parsing
+- **Safety limits** on delete loop (10,000 iterations + empty-batch exit)
+- **Thread-safe baseline loading** with `Lazy` and `LazyThreadSafetyMode.ExecutionAndPublication`
+- **Good precondition documentation** for internal `*Locked` methods
+- **Configurable regression threshold** via environment variable
+- **Correct lock ordering patterns** established in most methods
+
+### Major Concerns
+
+| Severity | Issue | Impact |
+|----------|-------|--------|
+| P0 | Nested scope creation in `CreateAndSaveInternal` → `Save()` | Transaction overhead, pattern violation |
+| P0 | Nested scope in `CreateAndSaveInternal` → `GetContentType()` | Conflicting locks possible |
+| P0 | `GetAncestors` path parsing with unhandled `FormatException` | Runtime crash on malformed data |
+| P1 | Lock acquisition timing inconsistency (single vs batch Save) | TOCTOU race in batch Save |
+
+---
+
+## 2. Critical Issues (P0 - Must Fix Before Implementation)
+
+### 2.1 CreateAndSaveInternal Creates Nested Scopes via Save()
+
+**Location:** Task 3, lines 849-875 (`CreateAndSaveInternal`) and lines 1085-1158 (`Save`)
+
+**Problem:** `CreateAndSaveInternal` creates a scope at line 851, then calls `Save(content, userId)` at line 871. But `Save()` creates its **own scope** at line 1089. This results in nested scopes with double lock acquisition.
+
+```csharp
+// CreateAndSaveInternal (line 851)
+private IContent CreateAndSaveInternal(...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope()) // SCOPE 1
+ {
+ scope.WriteLock(Constants.Locks.ContentTree); // LOCK 1
+ // ...
+ Save(content, userId); // Calls Save() below
+ scope.Complete();
+ }
+}
+
+// Save() (line 1089)
+public OperationResult Save(IContent content, int? userId = null, ...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope()) // SCOPE 2 (nested!)
+ {
+ scope.WriteLock(Constants.Locks.ContentTree); // LOCK 2 (redundant!)
+ // ...
+ }
+}
+```
+
+**Why It Matters:**
+- Creates unnecessary nested transaction overhead
+- Double-locking `ContentTree` is wasteful (nested scopes inherit parent lock, but still incur overhead)
+- Violates the pattern established by `DeleteLocked` and `GetPagedDescendantsLocked` which specifically avoid nested scopes
+- Inconsistent with the plan's stated goal of fixing nested scope issues
+
+**Recommended Fix:** Extract `SaveLocked()` private method that assumes caller holds scope:
+
+```csharp
+///
+/// Internal save implementation. Caller MUST hold scope with ContentTree write lock.
+///
+private OperationResult SaveLocked(ICoreScope scope, IContent content, int userId,
+ ContentScheduleCollection? contentSchedule, EventMessages eventMessages)
+{
+ // Validation (already under lock)
+ PublishedState publishedState = content.PublishedState;
+ if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
+ {
+ throw new InvalidOperationException(...);
+ }
+ // ... rest of save logic without scope creation ...
+}
+
+public OperationResult Save(IContent content, int? userId = null, ...)
+{
+ EventMessages eventMessages = EventMessagesFactory.Get();
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ scope.WriteLock(Constants.Locks.ContentTree);
+ var result = SaveLocked(scope, content, userId ?? Constants.Security.SuperUserId,
+ contentSchedule, eventMessages);
+ scope.Complete();
+ return result;
+ }
+}
+
+private IContent CreateAndSaveInternal(...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ scope.WriteLock(Constants.Locks.ContentTree, Constants.Locks.ContentTypes);
+ // ...
+ SaveLocked(scope, content, userId, null, EventMessagesFactory.Get());
+ scope.Complete();
+ return content;
+ }
+}
+```
+
+---
+
+### 2.2 GetContentType Creates Nested Scope When Called From CreateAndSaveInternal
+
+**Location:** Task 3, line 862 (`CreateAndSaveInternal`) and lines 1355-1361 (`GetContentType`)
+
+**Problem:** `CreateAndSaveInternal` already holds a scope (line 851), but calls `GetContentType()` at line 862, which creates **another scope** at line 1357 with a different lock.
+
+```csharp
+// CreateAndSaveInternal (has scope with ContentTree write lock)
+using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+{
+ scope.WriteLock(Constants.Locks.ContentTree);
+ // ...
+ IContentType contentType = GetContentType(contentTypeAlias); // NESTED SCOPE!
+}
+
+// GetContentType (line 1357)
+private IContentType GetContentType(string alias)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true)) // NESTED!
+ {
+ scope.ReadLock(Constants.Locks.ContentTypes); // Different lock!
+ return GetContentTypeLocked(alias);
+ }
+}
+```
+
+**Why It Matters:**
+- Creates nested scopes which the plan explicitly set out to fix
+- Acquires `ContentTypes` read lock inside `ContentTree` write lock scope (potential lock ordering issues)
+- Inconsistent with `GetContentTypeLocked()` which exists but isn't used here
+
+**Recommended Fix:** Acquire both locks upfront in `CreateAndSaveInternal` and use the `*Locked` variant:
+
+```csharp
+private IContent CreateAndSaveInternal(...)
+{
+ using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+ {
+ // Acquire both locks at scope start
+ scope.WriteLock(Constants.Locks.ContentTree);
+ scope.ReadLock(Constants.Locks.ContentTypes);
+
+ if (parent?.Trashed == true)
+ {
+ throw new InvalidOperationException(...);
+ }
+
+ // Use locked variant - no nested scope
+ IContentType contentType = GetContentTypeLocked(contentTypeAlias);
+
+ Content content = parent is not null
+ ? new Content(name, parent, contentType, userId)
+ : new Content(name, parentId, contentType, userId);
+
+ SaveLocked(scope, content, userId, null, EventMessagesFactory.Get());
+
+ scope.Complete();
+ return content;
+ }
+}
+```
+
+---
+
+### 2.3 GetAncestors Path Parsing Can Throw Unhandled FormatException
+
+**Location:** Task 3, lines 996-1005
+
+**Problem:** Path segments are parsed with `int.Parse()` without exception handling:
+
+```csharp
+var ancestorIds = content.Path
+ .Split(',')
+ .Skip(1) // Skip root (-1)
+ .Select(int.Parse) // CAN THROW FormatException!
+ .Where(id => id != content.Id)
+ .ToArray();
+```
+
+**Why It Matters:**
+- If `Path` contains malformed data (e.g., `-1,abc,456` from data corruption or import), this throws an unhandled `FormatException`
+- Crashes the entire request with an opaque error
+- No logging to help diagnose the root cause
+- The existing ContentService doesn't have this code path (it uses iterative `GetParent`), so this is a new failure mode
+
+**Recommended Fix - Option A (Defensive with TryParse):**
+
+```csharp
+var ancestorIds = content.Path
+ .Split(',')
+ .Skip(1)
+ .Select(s => int.TryParse(s, out var id) ? id : (int?)null)
+ .Where(id => id.HasValue && id.Value != content.Id)
+ .Select(id => id!.Value)
+ .ToArray();
+
+if (ancestorIds.Length == 0 && content.Level > 1)
+{
+ _logger.LogWarning("Malformed path '{Path}' for content {ContentId} at level {Level}",
+ content.Path, content.Id, content.Level);
+}
+```
+
+**Recommended Fix - Option B (Fail-safe with logging):**
+
+```csharp
+int[] ancestorIds;
+try
+{
+ ancestorIds = content.Path
+ .Split(',')
+ .Skip(1)
+ .Select(int.Parse)
+ .Where(id => id != content.Id)
+ .ToArray();
+}
+catch (FormatException ex)
+{
+ _logger.LogError(ex, "Malformed path '{Path}' for content {ContentId}, returning empty ancestors",
+ content.Path, content.Id);
+ return Enumerable.Empty();
+}
+```
+
+Option A is preferred as it's more resilient and handles partial corruption gracefully.
+
+---
+
+## 3. High Priority Issues (P1 - Should Fix)
+
+### 3.1 Lock Acquisition Timing Inconsistency Between Single and Batch Save
+
+**Location:** Task 3, lines 1089-1114 (single Save) vs. lines 1166-1177 (batch Save)
+
+**Problem:** The two Save overloads have inconsistent lock/notification ordering:
+
+| Operation | Order |
+|-----------|-------|
+| Single Save | Scope → WriteLock → Validate → Notification → Repository |
+| Batch Save | Scope → Notification → WriteLock → Repository |
+
+```csharp
+// Single Save (lines 1089-1114) - Lock BEFORE notification
+using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+{
+ scope.WriteLock(Constants.Locks.ContentTree); // LOCK FIRST
+
+ // Validate AFTER lock (content state is stable)
+ PublishedState publishedState = content.PublishedState;
+ if (publishedState != PublishedState.Published && ...)
+
+ var savingNotification = new ContentSavingNotification(...);
+ if (scope.Notifications.PublishCancelable(savingNotification))
+ // ...
+}
+
+// Batch Save (lines 1166-1177) - Notification BEFORE lock
+using (ICoreScope scope = ScopeProvider.CreateCoreScope())
+{
+ var savingNotification = new ContentSavingNotification(contentsA, eventMessages);
+ if (scope.Notifications.PublishCancelable(savingNotification)) // NOTIFICATION FIRST
+ {
+ scope.Complete();
+ return OperationResult.Cancel(eventMessages);
+ }
+
+ scope.WriteLock(Constants.Locks.ContentTree); // LOCK SECOND
+ // ...
+}
+```
+
+**Why It Matters:**
+- The plan explicitly states "Validate AFTER acquiring lock — content state is now stable" for single Save
+- But batch Save sends notification before lock, so handlers see potentially stale state
+- Creates TOCTOU race (content could change between notification and lock)
+- Inconsistent behavior is confusing for notification handlers
+
+**Note:** Looking at the original ContentService, single Save also publishes notification before acquiring lock (lines 1107-1114 in original). The plan CHANGES single Save to lock-first. This is a behavioral change that should be documented.
+
+**Recommended Fix:**
+1. If the plan intends to change lock timing for safety, apply consistently to both overloads
+2. Document this as a behavioral change in the summary section
+3. Or revert single Save to match original (notification before lock) for consistency
+
+---
+
+### 3.2 Unit Test Missing IsolationLevel Import
+
+**Location:** Task 3, lines 601-609 (`CreateMockScopeWithReadLock` helper)
+
+**Problem:** The helper method references `IsolationLevel` without a visible using statement:
+
+```csharp
+_scopeProvider.Setup(x => x.CreateCoreScope(
+ It.IsAny(), // IsolationLevel needs import
+ It.IsAny(),
+ // ...
+```
+
+**Why It Matters:** Build will fail without the correct import.
+
+**Recommended Fix:** Add to test file imports:
+
+```csharp
+using IsolationLevel = System.Data.IsolationLevel;
+```
+
+Or use fully qualified name in the test.
+
+---
+
+### 3.3 Batch Save Missing Validation That Exists in Single Save
+
+**Location:** Task 3, lines 1166-1204 (batch Save)
+
+**Problem:** Single Save validates `PublishedState` and name length (lines 1094-1104), but batch Save doesn't perform these validations:
+
+```csharp
+// Single Save has this validation:
+PublishedState publishedState = content.PublishedState;
+if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
+{
+ throw new InvalidOperationException(...);
+}
+
+if (content.Name != null && content.Name.Length > 255)
+{
+ throw new InvalidOperationException(...);
+}
+
+// Batch Save SKIPS this validation entirely
+```
+
+**Why It Matters:**
+- Allows saving content in invalid states via batch API
+- Name length constraint only enforced for single saves
+- Inconsistent validation behavior
+
+**Note:** This matches the original ContentService behavior (batch Save also lacks validation). If maintaining parity, document this explicitly as a known limitation.
+
+**Recommended Fix:** Either:
+1. Add validation loop in batch Save (with option to collect all errors before throwing)
+2. Document this as intentional parity with original behavior
+
+---
+
+## 4. Minor Issues & Improvements (P2)
+
+### 4.1 GetByIds Nullable Handling Inconsistency
+
+**Location:** Task 3, lines 902-917 (int overload) vs. lines 922-944 (Guid overload)
+
+**Problem:** The Guid overload checks `if (items is not null)` at line 940, but the int overload doesn't:
+
+```csharp
+// Int overload (no null check)
+IEnumerable items = DocumentRepository.GetMany(idsA);
+var index = items.GroupBy(x => x.Id).ToDictionary(...);
+
+// Guid overload (has null check)
+IEnumerable? items = DocumentRepository.GetMany(idsA);
+if (items is not null)
+{
+ var index = items.GroupBy(x => x.Key).ToDictionary(...);
+ // ...
+}
+```
+
+**Recommended Fix:** Apply consistent null handling to both overloads. The int overload should also handle potential null from repository.
+
+---
+
+### 4.2 Interface Method Count Discrepancy in Summary
+
+**Location:** Summary section, "Interface Methods (24 total)"
+
+**Problem:** Summary claims 24 methods, but counting the interface definition in Task 2:
+- Create: 6 methods
+- Read: 7 methods (GetById×2, GetByIds×2, GetRootContent, GetParent×2)
+- Read Tree: 5 methods (GetAncestors×2, GetPagedChildren, GetPagedDescendants, HasChildren)
+- Exists: 2 methods
+- Save: 2 methods
+- Delete: 1 method
+
+Total: **23 public interface methods**, not 24.
+
+**Recommended Fix:** Update summary to accurate count.
+
+---
+
+### 4.3 Warmup Exception Silently Swallowed
+
+**Location:** Task 6, lines 1806-1809
+
+**Problem:** Warmup iteration swallows all exceptions with empty catch:
+
+```csharp
+if (!skipWarmup)
+{
+ try { action(); }
+ catch { /* Warmup failure acceptable */ }
+}
+```
+
+**Why It Matters:** Could hide setup issues that cause actual measurement to fail unexpectedly.
+
+**Recommended Fix:** Log warmup failures at Debug level:
+
+```csharp
+if (!skipWarmup)
+{
+ try { action(); }
+ catch (Exception ex)
+ {
+ TestContext.WriteLine($"[WARMUP] {name} warmup failed: {ex.Message}");
+ }
+}
+```
+
+---
+
+### 4.4 Benchmark Threshold Edge Case
+
+**Location:** Task 6, threshold table and line 1787
+
+**Problem:** The threshold comparison uses `>`:
+
+```csharp
+if (elapsedMs > maxAllowed)
+```
+
+For `Save_SingleItem` with baseline 7ms at 20% threshold, max allowed is exactly 8.4ms. If measurement is exactly 8.4ms, it passes. This is correct, but floating-point representation of 8.4 could cause unexpected boundary behavior.
+
+**Recommended Fix:** Document that boundary is inclusive (`<=` max), or use integer math:
+
+```csharp
+var maxAllowed = (long)Math.Ceiling(baselineResult.ElapsedMs * (1 + effectiveThreshold / 100));
+```
+
+---
+
+### 4.5 Task 5 Step 3 Lazy Pattern Could Be Simplified
+
+**Location:** Task 5, Step 3
+
+**Problem:** The plan describes using `Lazy` for obsolete constructors, but the primary constructor sets `_crudServiceLazy = null!`:
+
+```csharp
+_crudService = crudService ?? throw new ArgumentNullException(nameof(crudService));
+_crudServiceLazy = null!; // Not used when directly injected
+```
+
+This means `CrudService` property could throw NullReferenceException if incorrectly accessed:
+
+```csharp
+private IContentCrudService CrudService => _crudService ?? _crudServiceLazy.Value;
+```
+
+If `_crudService` is null AND `_crudServiceLazy` is null, this throws.
+
+**Recommended Fix:** Use null-forgiving operator more carefully or use single field with union pattern:
+
+```csharp
+private readonly Lazy _crudServiceLazy;
+
+// In primary constructor:
+_crudServiceLazy = new Lazy(() => crudService);
+
+// In obsolete constructors:
+_crudServiceLazy = new Lazy(() =>
+ StaticServiceProvider.Instance.GetRequiredService());
+
+// Property:
+private IContentCrudService CrudService => _crudServiceLazy.Value;
+```
+
+---
+
+## 5. Questions for Clarification
+
+1. **Nested Scope Intent:** Is `CreateAndSaveInternal` calling `Save()` (which creates its own scope) intentional, or should it use a `SaveLocked()` variant as recommended?
+
+2. **Validation Timing Change:** The plan moves single-item Save validation inside the locked section (after `WriteLock`). The original ContentService validates before scope creation. Is this intentional behavioral change, and should it be documented?
+
+3. **ContentSchedule Parity:** The plan documents that batch Save doesn't support content schedules. Does the original ContentService batch Save support schedules? If so, this needs to be called out as a behavioral difference.
+
+4. **Lock Ordering Strategy:** When `CreateAndSaveInternal` needs both `ContentTree` (write) and `ContentTypes` (read) locks, should they be acquired in a specific order for deadlock prevention? The codebase should document lock ordering conventions.
+
+---
+
+## 6. Final Recommendation
+
+### Verdict: **Major Revisions Needed**
+
+The plan requires fixes for the three P0 issues before implementation can proceed safely.
+
+### Required Changes Before Approval
+
+| Priority | Issue | Recommended Fix |
+|----------|-------|-----------------|
+| **P0** | `CreateAndSaveInternal` → `Save()` nested scope | Extract `SaveLocked()` internal method |
+| **P0** | `CreateAndSaveInternal` → `GetContentType()` nested scope | Acquire both locks upfront, use `GetContentTypeLocked()` |
+| **P0** | `GetAncestors` `int.Parse` FormatException | Use `TryParse` with logging |
+| **P1** | Batch Save notification before lock (inconsistent) | Align with single Save or document difference |
+| **P1** | Missing `IsolationLevel` import | Add using statement |
+| **P1** | Batch Save missing validation | Document as intentional or add validation |
+| **P2** | GetByIds null handling inconsistency | Align both overloads |
+| **P2** | Method count in summary | Fix to 23 |
+| **P2** | Warmup exception logging | Add Debug-level logging |
+
+### Positive Notes
+
+The plan is fundamentally sound. The three prior reviews have significantly improved robustness:
+- Thread-safe baseline loading
+- Delete loop safety bounds
+- N+1 query elimination in GetAncestors
+- Comprehensive precondition documentation
+
+After addressing the P0 issues (primarily around nested scope creation), this plan will be ready for implementation. The issues identified are localized and can be fixed with targeted changes to Tasks 3 and 5.
+
+---
+
+## 7. Appendix: Referenced Code Locations
+
+| File | Lines | Description |
+|------|-------|-------------|
+| Plan Task 3 | 849-875 | `CreateAndSaveInternal` implementation |
+| Plan Task 3 | 1085-1158 | `Save(IContent)` implementation |
+| Plan Task 3 | 1166-1204 | `Save(IEnumerable)` implementation |
+| Plan Task 3 | 996-1005 | `GetAncestors` path parsing |
+| Plan Task 3 | 1355-1361 | `GetContentType` with scope |
+| Plan Task 5 | 1543-1571 | Constructor with `Lazy` pattern |
+| Plan Task 6 | 1770-1798 | `AssertNoRegression` implementation |
+| Original ContentService | 1088-1138 | Original `Save` implementation (for comparison) |
+| Original ContentService | 2322-2345 | Original `DeleteLocked` (for pattern reference) |
+
+---
+
+**Review Complete.** Awaiting plan revision for P0 issues before implementation approval.
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-5.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-5.md
new file mode 100644
index 0000000000..1d020910d5
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation-critical-review-5.md
@@ -0,0 +1,445 @@
+# Critical Implementation Review #5: Phase 1 ContentService CRUD Extraction
+
+**Plan**: `docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md` (v1.5)
+**Reviewer**: Claude (Critical Implementation Review)
+**Date**: 2025-12-20
+**Review Type**: Strict Code Review (Pre-Implementation)
+
+---
+
+## 1. Overall Assessment
+
+### Strengths
+
+- **Thorough iteration**: Plan v1.5 incorporates feedback from 4 prior critical reviews with detailed change tracking
+- **Well-documented versioning strategy**: Clear interface extensibility model and deprecation policy
+- **Proper nested scope elimination**: Extracted `SaveLocked`, `GetContentTypeLocked`, `GetPagedDescendantsLocked` to avoid nested scope creation
+- **Thread-safe patterns**: Lazy initialization with `LazyThreadSafetyMode.ExecutionAndPublication` for baseline loading and service resolution
+- **Comprehensive implementation checklist**: All 30+ items from prior reviews tracked with checkboxes
+- **TDD approach**: Unit tests defined before implementation code
+
+### Major Concerns
+
+1. **Critical lock ordering gap** when saving variant (multi-language) content
+2. **Inconsistent cancellation behavior** between single and batch Save operations
+3. **Underspecified constructor modifications** for obsolete ContentService constructors
+
+---
+
+## 2. Critical Issues (P0 - Must Fix Before Implementation)
+
+### 2.1 Missing Languages Lock When Saving Variant Content
+
+**Location**: Lines 1110-1124 (`Save(IContent)`) and lines 1142-1204 (`SaveLocked`)
+
+**Description**:
+
+The `SaveLocked` method calls `GetLanguageDetailsForAuditEntryLocked(culturesChanging)` at lines 1195-1196. This locked variant has a documented precondition:
+
+> "Caller MUST hold an active scope with read/write lock on `Constants.Locks.Languages`."
+
+However, neither `Save()` nor `CreateAndSaveInternal()` acquire this lock:
+
+```csharp
+// Save() - line 1117 - only acquires ContentTree:
+scope.WriteLock(Constants.Locks.ContentTree);
+// Languages lock is NOT acquired
+
+var result = SaveLocked(scope, content, ...); // Calls GetLanguageDetailsForAuditEntryLocked
+```
+
+```csharp
+// CreateAndSaveInternal() - lines 861-862:
+scope.WriteLock(Constants.Locks.ContentTree);
+scope.ReadLock(Constants.Locks.ContentTypes);
+// Languages lock is NOT acquired
+
+SaveLocked(scope, content, ...); // Calls GetLanguageDetailsForAuditEntryLocked
+```
+
+**Impact**:
+
+| Risk | Description |
+|------|-------------|
+| Data Consistency | `_languageRepository.GetMany()` called without lock protection in multi-threaded scenarios |
+| Deadlock Potential | Another operation holding Languages lock and waiting for ContentTree could deadlock |
+| Lock Hierarchy Violation | Breaks the documented lock ordering strategy |
+
+**Affected Scenarios**: All saves of variant (multi-language) content where `culturesChanging != null`
+
+**Actionable Fix**:
+
+Option A (Recommended): Acquire Languages lock in all Save paths:
+
+```csharp
+// In Save():
+scope.WriteLock(Constants.Locks.ContentTree);
+scope.ReadLock(Constants.Locks.Languages); // ADD THIS
+
+// In CreateAndSaveInternal():
+scope.WriteLock(Constants.Locks.ContentTree);
+scope.ReadLock(Constants.Locks.ContentTypes);
+scope.ReadLock(Constants.Locks.Languages); // ADD THIS
+```
+
+Option B (Alternative): Conditionally acquire lock only when needed:
+
+```csharp
+// In SaveLocked, before accessing languages:
+if (culturesChanging != null)
+{
+ scope.ReadLock(Constants.Locks.Languages);
+ var langs = GetLanguageDetailsForAuditEntryLocked(culturesChanging);
+ // ...
+}
+```
+
+**Recommendation**: Option A is safer and simpler. The overhead of acquiring an unused read lock is minimal compared to the complexity of conditional locking.
+
+---
+
+### 2.2 Batch Save Inconsistent scope.Complete() on Cancellation
+
+**Location**: Lines 1231-1234 in batch `Save(IEnumerable)`
+
+**Description**:
+
+When `ContentSavingNotification` is cancelled, batch Save calls `scope.Complete()`:
+
+```csharp
+if (scope.Notifications.PublishCancelable(savingNotification))
+{
+ _logger.LogInformation("Batch save operation cancelled...");
+ scope.Complete(); // <-- INCONSISTENT
+ return OperationResult.Cancel(eventMessages);
+}
+```
+
+Comparison with other operations:
+
+| Operation | On Cancel | Code Location |
+|-----------|-----------|---------------|
+| `Save(IContent)` single | No `scope.Complete()` | Lines 1160-1165 |
+| `Save(IEnumerable)` batch | **Calls `scope.Complete()`** | Lines 1231-1234 |
+| `Delete(IContent)` | No `scope.Complete()` | Lines 1277-1280 |
+
+**Impact**:
+
+- Inconsistent behavior between single and batch operations
+- Semantically questionable: what transaction is being committed on cancellation?
+- Could commit partial work if any side effects occurred before notification
+
+**Actionable Fix**:
+
+Remove `scope.Complete()` from the cancellation path to match single-item Save behavior:
+
+```csharp
+if (scope.Notifications.PublishCancelable(savingNotification))
+{
+ _logger.LogInformation("Batch save operation cancelled for {ContentCount} content items by notification handler",
+ contentsA.Length);
+ return OperationResult.Cancel(eventMessages); // No scope.Complete()
+}
+```
+
+---
+
+## 3. High Priority Issues (P1 - Should Fix)
+
+### 3.1 Task 5 Obsolete Constructor Modification Underspecified
+
+**Location**: Task 5, Steps 1-3
+
+**Description**:
+
+The plan describes using `Lazy` for obsolete constructors but doesn't show complete constructor modifications. The existing ContentService has two obsolete constructors (lines 91-169) that chain to the primary constructor via `: this(...)`.
+
+**Current pattern (simplified)**:
+```csharp
+[Obsolete("...")]
+public ContentService(/* old params */)
+ : this(/* chain to primary constructor */)
+{
+}
+```
+
+**Unclear aspects**:
+1. How does chaining work when primary constructor now requires `IContentCrudService`?
+2. Do both obsolete constructors need identical treatment?
+3. What is the complete body of modified obsolete constructors?
+
+**Actionable Fix**:
+
+Provide complete obsolete constructor specification. The obsolete constructors should NOT chain to the new primary constructor. Instead, they should have their own full body:
+
+```csharp
+[Obsolete("Use the non-obsolete constructor instead. Scheduled removal in v19.")]
+public ContentService(
+ ICoreScopeProvider provider,
+ ILoggerFactory loggerFactory,
+ IEventMessagesFactory eventMessagesFactory,
+ IDocumentRepository documentRepository,
+ IEntityRepository entityRepository,
+ IAuditRepository auditRepository, // Old parameter
+ IContentTypeRepository contentTypeRepository,
+ IDocumentBlueprintRepository documentBlueprintRepository,
+ ILanguageRepository languageRepository,
+ Lazy propertyValidationService,
+ IShortStringHelper shortStringHelper,
+ ICultureImpactFactory cultureImpactFactory,
+ IUserIdKeyResolver userIdKeyResolver,
+ PropertyEditorCollection propertyEditorCollection,
+ IIdKeyMap idKeyMap,
+ IOptionsMonitor optionsMonitor,
+ IRelationService relationService)
+ : base(provider, loggerFactory, eventMessagesFactory)
+{
+ // All existing field assignments...
+ _documentRepository = documentRepository;
+ _entityRepository = entityRepository;
+ // ... etc ...
+
+ // NEW: Lazy resolution of IContentCrudService
+ _crudServiceLazy = new Lazy(() =>
+ StaticServiceProvider.Instance.GetRequiredService(),
+ LazyThreadSafetyMode.ExecutionAndPublication);
+}
+```
+
+---
+
+### 3.2 Unit Tests Missing Variant Culture Save Path Coverage
+
+**Location**: Task 3, Step 1 (`ContentCrudServiceTests.cs`)
+
+**Description**:
+
+The unit tests cover basic scenarios but don't exercise the variant culture path in `SaveLocked` (lines 1175-1197), which:
+1. Checks `content.ContentType.VariesByCulture()`
+2. Accesses `content.CultureInfos`
+3. Calls `GetLanguageDetailsForAuditEntryLocked()`
+
+This is the exact code path affected by the critical lock bug (2.1).
+
+**Actionable Fix**:
+
+Add a unit test for variant content saving:
+
+```csharp
+[Test]
+public void Save_WithVariantContent_CallsLanguageRepository()
+{
+ // Arrange
+ var scope = CreateMockScopeWithWriteLock();
+
+ var contentType = new Mock();
+ contentType.Setup(x => x.VariesByCulture()).Returns(true);
+
+ var cultureInfo = new Mock();
+ cultureInfo.Setup(x => x.IsDirty()).Returns(true);
+ cultureInfo.Setup(x => x.Culture).Returns("en-US");
+
+ var cultureInfos = new Mock>();
+ cultureInfos.Setup(x => x.Values).Returns(new[] { cultureInfo.Object });
+
+ var content = new Mock();
+ content.Setup(x => x.ContentType).Returns(contentType.Object);
+ content.Setup(x => x.CultureInfos).Returns(cultureInfos.Object);
+ content.Setup(x => x.HasIdentity).Returns(true);
+ content.Setup(x => x.PublishedState).Returns(PublishedState.Unpublished);
+ content.Setup(x => x.Name).Returns("Test");
+
+ _languageRepository.Setup(x => x.GetMany()).Returns(new List());
+
+ // Act
+ var result = _sut.Save(content.Object);
+
+ // Assert
+ Assert.That(result.Success, Is.True);
+ _languageRepository.Verify(x => x.GetMany(), Times.Once);
+}
+```
+
+---
+
+## 4. Medium Priority Issues (P2 - Recommended)
+
+### 4.1 Missing Using Statements in Code Samples
+
+**Location**: Task 3, ContentCrudService.cs code block
+
+**Description**:
+
+The code uses types requiring imports not shown in the using block:
+- `TextColumnType` requires `Umbraco.Cms.Core.Persistence.Querying`
+- `Direction` requires `Umbraco.Cms.Core.Persistence.Querying`
+- `Ordering` requires `Umbraco.Cms.Core.Persistence.Querying`
+
+**Actionable Fix**:
+
+Add to the using statements at the top of ContentCrudService.cs:
+
+```csharp
+using Umbraco.Cms.Core.Persistence.Querying;
+```
+
+---
+
+### 4.2 RecordBenchmark vs AssertNoRegression Clarification
+
+**Location**: Task 6, Step 2
+
+**Description**:
+
+The plan adds `AssertNoRegression` which internally calls `RecordBenchmark`. The example shows calling `AssertNoRegression` only, which is correct. However, the instruction text could be clearer that benchmarks should REPLACE `RecordBenchmark` calls with `AssertNoRegression`, not add both.
+
+**Actionable Fix**:
+
+Update Step 2 text to:
+
+> "**Replace** `RecordBenchmark(...)` calls with `AssertNoRegression(...)` calls in the following 10 Phase 1 CRUD benchmarks. The `AssertNoRegression` method internally records the benchmark AND asserts no regression."
+
+---
+
+### 4.3 GetAncestors Warning Log Could Be Noisy
+
+**Location**: Lines 1024-1029
+
+**Description**:
+
+`GetAncestors` logs a warning when `ancestorIds.Length == 0 && content.Level > 1`:
+
+```csharp
+_logger.LogWarning(
+ "Malformed path '{Path}' for content {ContentId} at level {Level} - expected ancestors but found none",
+ content.Path, content.Id, content.Level);
+```
+
+This warning could be noisy in edge cases or during data migration.
+
+**Actionable Fix**:
+
+Consider changing to `LogDebug` or adding expected count for clarity:
+
+```csharp
+_logger.LogWarning(
+ "Malformed path '{Path}' for content {ContentId} at level {Level} - expected {ExpectedCount} ancestors but parsed {ActualCount}",
+ content.Path, content.Id, content.Level, content.Level - 1, ancestorIds.Length);
+```
+
+---
+
+### 4.4 Benchmark CI Failure Mode Consideration
+
+**Location**: Task 6, `AssertNoRegression` implementation
+
+**Description**:
+
+If the baseline file doesn't exist, `AssertNoRegression` logs and skips the regression check. In CI environments, this could mask regressions if the baseline file is missing.
+
+**Actionable Fix (Optional)**:
+
+Add optional strict mode via environment variable:
+
+```csharp
+private static readonly bool RequireBaseline =
+ bool.TryParse(Environment.GetEnvironmentVariable("BENCHMARK_REQUIRE_BASELINE"), out var b) && b;
+
+protected void AssertNoRegression(...)
+{
+ RecordBenchmark(name, elapsedMs, itemCount);
+
+ if (Baseline.TryGetValue(name, out var baselineResult))
+ {
+ // ... existing regression check ...
+ }
+ else if (RequireBaseline)
+ {
+ Assert.Fail($"No baseline entry found for '{name}' and BENCHMARK_REQUIRE_BASELINE=true");
+ }
+ else
+ {
+ TestContext.WriteLine($"[REGRESSION_CHECK] {name}: SKIPPED (no baseline entry)");
+ }
+}
+```
+
+---
+
+## 5. Questions for Clarification
+
+### Q1: Lock Ordering Strategy for Languages Lock
+
+When fixing issue 2.1, should the Languages lock be acquired:
+- **Always** in `Save()` and `CreateAndSaveInternal()` (simpler, minor overhead for invariant content), or
+- **Conditionally** only when `content.ContentType.VariesByCulture()` returns true (more complex, avoids unnecessary locks)?
+
+**Recommendation**: Always acquire. The read lock overhead is minimal.
+
+### Q2: Obsolete Constructor Strategy
+
+For the obsolete constructors:
+- Should they stop chaining to the primary constructor and have their own full body?
+- Or should an intermediate constructor be added that accepts optional `IContentCrudService`?
+
+**Recommendation**: Full body approach (as shown in fix 3.1) is cleaner and avoids parameter default complexity.
+
+### Q3: Baseline Required in CI
+
+Should the CI pipeline require baseline file presence? If so, add the `BENCHMARK_REQUIRE_BASELINE` environment variable check suggested in 4.4.
+
+---
+
+## 6. Implementation Checklist Additions
+
+Add to the existing checklist:
+
+### From Critical Review 5
+
+- [ ] `Save()` acquires `Constants.Locks.Languages` read lock
+- [ ] `CreateAndSaveInternal()` acquires `Constants.Locks.Languages` read lock
+- [ ] Batch `Save()` does NOT call `scope.Complete()` on cancellation
+- [ ] Obsolete constructors have complete body specification (not chained)
+- [ ] Unit test added for variant culture save path
+- [ ] `using Umbraco.Cms.Core.Persistence.Querying;` added to ContentCrudService.cs
+- [ ] Task 6 Step 2 clarifies "replace" not "add" AssertNoRegression
+
+---
+
+## 7. Final Recommendation
+
+| Verdict | **Major Revisions Needed** |
+|---------|----------------------------|
+
+The plan is comprehensive and well-structured after 4 prior reviews, but the **missing Languages lock** (Issue 2.1) is a correctness bug that will affect all multi-language content saves. This must be fixed before implementation.
+
+### Required Changes (Blocking)
+
+| Priority | Issue | Action |
+|----------|-------|--------|
+| P0 | 2.1 Missing Languages Lock | Acquire `scope.ReadLock(Constants.Locks.Languages)` in `Save()` and `CreateAndSaveInternal()` |
+| P0 | 2.2 Inconsistent scope.Complete() | Remove `scope.Complete()` from batch Save cancellation path |
+| P1 | 3.1 Constructor Underspecified | Add complete obsolete constructor body to Task 5 |
+
+### Recommended Changes (Non-Blocking)
+
+| Priority | Issue | Action |
+|----------|-------|--------|
+| P1 | 3.2 Missing Test Coverage | Add unit test for variant culture save |
+| P2 | 4.1 Using Statements | Add missing using to code sample |
+| P2 | 4.2 Task 6 Clarification | Clarify "replace" RecordBenchmark |
+
+---
+
+## 8. Summary
+
+**Plan Version**: 1.5
+**Critical Issues Found**: 2
+**High Priority Issues Found**: 2
+**Medium Priority Issues Found**: 4
+
+After addressing the critical lock ordering issue and scope.Complete() inconsistency, the plan will be production-ready. The prior 4 reviews have successfully caught and fixed the majority of implementation concerns—this review identified edge cases in the variant content save path that were not fully covered.
+
+---
+
+*Review completed: 2025-12-20*
diff --git a/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md
new file mode 100644
index 0000000000..e0b1f848ca
--- /dev/null
+++ b/docs/plans/2025-12-20-contentservice-refactor-phase1-implementation.md
@@ -0,0 +1,2405 @@
+# ContentService CRUD Extraction - Phase 1 Implementation Plan
+
+> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
+
+**Goal:** Extract CRUD operations (Create, Get, Save, Delete) from ContentService into a dedicated `IContentCrudService` interface and `ContentCrudService` implementation.
+
+**Architecture:** Create a shared `ContentServiceBase` abstract class containing common dependencies and infrastructure. `ContentCrudService` implements `IContentCrudService` and inherits from `ContentServiceBase`. The existing `ContentService` facade will delegate to `ContentCrudService` for CRUD operations.
+
+**Tech Stack:** .NET 10.0, NUnit, Microsoft.Extensions.DependencyInjection
+
+---
+
+## Plan Version History
+
+| Version | Date | Author | Changes |
+|---------|------|--------|---------|
+| 1.0 | 2025-12-20 | Claude | Initial plan creation |
+| 1.1 | 2025-12-20 | Claude | Applied critical review feedback (see "Critical Review Changes Applied" section) |
+| 1.2 | 2025-12-20 | Claude | Added versioning strategy and plan version history |
+| 1.3 | 2025-12-20 | Claude | Applied second critical review feedback (see "Critical Review 2 Changes Applied" section) |
+| 1.4 | 2025-12-20 | Claude | Applied third critical review feedback (see "Critical Review 3 Changes Applied" section) |
+| 1.5 | 2025-12-20 | Claude | Applied fourth critical review feedback (see "Critical Review 4 Changes Applied" section) |
+| 1.6 | 2025-12-20 | Claude | Applied fifth critical review feedback (see "From Critical Review 5" checklist section) |
+
+---
+
+## Versioning Strategy
+
+### Interface Versioning (`IContentCrudService`)
+
+**Policy:** The `IContentCrudService` interface follows **additive-only changes** until a major version bump.
+
+| Change Type | Allowed? | Action Required |
+|-------------|----------|-----------------|
+| Add new method | ✅ Yes | Add with default implementation in abstract base class |
+| Remove method | ❌ No | Mark `[Obsolete]` for 2 major versions, then remove |
+| Change method signature | ❌ No | Add new overload, deprecate old |
+| Change return type | ❌ No | Add new method with different name |
+| Add optional parameter | ✅ Yes | Use default value |
+
+**Breaking Change Process:**
+1. Mark existing member with `[Obsolete("Use X instead. Will be removed in v{N+2}.")]`
+2. Add replacement member
+3. Update all internal usages to new member
+4. Remove in version N+2 (minimum 2 major version grace period)
+
+### Interface Extensibility Model
+
+`IContentCrudService` is designed for **composition, not direct implementation**.
+
+**Supported usage:**
+- Inject `IContentCrudService` as a dependency ✅
+- Extend `ContentCrudService` via inheritance ✅
+- Replace registration in DI with custom implementation inheriting `ContentServiceBase` ✅
+
+**Unsupported usage:**
+- Implement `IContentCrudService` directly without inheriting `ContentServiceBase` ❌
+
+**Rationale:** All CRUD operations require shared infrastructure (scoping, repositories,
+auditing). `ContentServiceBase` provides this infrastructure. Direct interface implementation
+would require re-implementing this infrastructure correctly, which is error-prone and
+creates maintenance burden.
+
+**Adding New Methods (Umbraco internal process):**
+1. Add method signature to `IContentCrudService` interface
+2. Add virtual implementation to `ContentServiceBase` (if shareable) or `ContentCrudService`
+3. Existing subclasses automatically inherit the new implementation
+4. Mark with `[Since("X.Y")]` attribute if adding after initial release
+
+### Obsolete Constructor Support Duration
+
+Obsolete constructors on `ContentService` that use the `Lazy` pattern:
+- **Support duration:** 2 major versions (e.g., introduced in v14, removed in v16)
+- **Warning level:** Compile-time warning via `[Obsolete]` attribute
+- **Migration path:** Update to primary constructor with direct `IContentCrudService` injection
+
+### Semantic Versioning Alignment
+
+This refactoring aligns with Umbraco's semantic versioning:
+- **Major (X.0.0):** Breaking changes allowed (interface method removal, signature changes)
+- **Minor (X.Y.0):** New features, additive interface changes only
+- **Patch (X.Y.Z):** Bug fixes, no interface changes
+
+---
+
+## Phase 1 Overview
+
+Phase 1 establishes the foundational patterns for the entire refactoring:
+
+1. **ContentServiceBase** - Abstract base class with shared dependencies
+2. **IContentCrudService** - Interface for CRUD operations
+3. **ContentCrudService** - Implementation of CRUD operations
+4. **DI Registration** - Register new services alongside existing ContentService
+5. **ContentService Delegation** - Update facade to delegate to new service
+
+The existing `ContentService` (3823 lines) will shrink as we extract methods to `ContentCrudService`.
+
+---
+
+## Task 1: Create ContentServiceBase Abstract Class
+
+**Files:**
+- Create: `src/Umbraco.Core/Services/ContentServiceBase.cs`
+
+**Step 1: Write the failing test**
+
+The tracking test already exists in `ContentServiceBaseTests.cs`. It will pass once we create the class.
+
+**Step 2: Create the abstract base class**
+
+```csharp
+// src/Umbraco.Core/Services/ContentServiceBase.cs
+using Microsoft.Extensions.Logging;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Persistence.Querying;
+using Umbraco.Cms.Core.Persistence.Repositories;
+using Umbraco.Cms.Core.Scoping;
+
+namespace Umbraco.Cms.Core.Services;
+
+///
+/// Abstract base class for content-related services providing shared infrastructure.
+///
+public abstract class ContentServiceBase : RepositoryService
+{
+ protected readonly IDocumentRepository DocumentRepository;
+ protected readonly IAuditService AuditService;
+ protected readonly IUserIdKeyResolver UserIdKeyResolver;
+
+ protected ContentServiceBase(
+ ICoreScopeProvider provider,
+ ILoggerFactory loggerFactory,
+ IEventMessagesFactory eventMessagesFactory,
+ IDocumentRepository documentRepository,
+ IAuditService auditService,
+ IUserIdKeyResolver userIdKeyResolver)
+ : base(provider, loggerFactory, eventMessagesFactory)
+ {
+ DocumentRepository = documentRepository ?? throw new ArgumentNullException(nameof(documentRepository));
+ AuditService = auditService ?? throw new ArgumentNullException(nameof(auditService));
+ UserIdKeyResolver = userIdKeyResolver ?? throw new ArgumentNullException(nameof(userIdKeyResolver));
+ }
+
+ ///
+ /// Records an audit entry for a content operation (synchronous).
+ ///
+ ///
+ /// Uses ConfigureAwait(false) to avoid capturing synchronization context and prevent deadlocks.
+ /// TODO: Replace with sync overloads when IAuditService.Add and IUserIdKeyResolver.Get are available.
+ ///
+ protected void Audit(AuditType type, int userId, int objectId, string? message = null, string? parameters = null)
+ {
+ // Use ConfigureAwait(false) to avoid context capture and potential deadlocks
+ Guid userKey = UserIdKeyResolver.GetAsync(userId).ConfigureAwait(false).GetAwaiter().GetResult();
+
+ AuditService.AddAsync(
+ type,
+ userKey,
+ objectId,
+ UmbracoObjectTypes.Document.GetName(),
+ message,
+ parameters).ConfigureAwait(false).GetAwaiter().GetResult();
+ }
+
+ ///
+ /// Records an audit entry for a content operation asynchronously.
+ ///
+ protected async Task AuditAsync(AuditType type, int userId, int objectId, string? message = null, string? parameters = null)
+ {
+ Guid userKey = await UserIdKeyResolver.GetAsync(userId).ConfigureAwait(false);
+
+ await AuditService.AddAsync(
+ type,
+ userKey,
+ objectId,
+ UmbracoObjectTypes.Document.GetName(),
+ message,
+ parameters).ConfigureAwait(false);
+ }
+}
+```
+
+**Step 3: Add ContentServiceConstants class**
+
+```csharp
+// src/Umbraco.Core/Services/ContentServiceConstants.cs
+namespace Umbraco.Cms.Core.Services;
+
+///
+/// Constants used by content-related services.
+///
+public static class ContentServiceConstants
+{
+ ///
+ /// Default page size for batch operations (e.g., cascade delete).
+ ///
+ public const int DefaultBatchPageSize = 500;
+}
+```
+
+**Step 4: Verify the project builds**
+
+Run: `dotnet build src/Umbraco.Core/Umbraco.Core.csproj`
+Expected: Build succeeded.
+
+**Step 5: Run the tracking test**
+
+Run: `dotnet test tests/Umbraco.Tests.Integration --filter "FullyQualifiedName~ContentServiceBaseTests"`
+Expected: Test passes (class now exists)
+
+**Step 6: Commit**
+
+```bash
+git add src/Umbraco.Core/Services/ContentServiceBase.cs src/Umbraco.Core/Services/ContentServiceConstants.cs
+git commit -m "$(cat <<'EOF'
+feat(core): add ContentServiceBase abstract class for Phase 1
+
+Establishes shared infrastructure for content services:
+- Common dependencies (DocumentRepository, AuditService, UserIdKeyResolver)
+- Audit helper methods
+- Inherits from RepositoryService for scope/query support
+- Adds ContentServiceConstants for shared constants (batch page size)
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 2: Create IContentCrudService Interface
+
+**Files:**
+- Create: `src/Umbraco.Core/Services/IContentCrudService.cs`
+
+**Step 1: Create the interface**
+
+```csharp
+// src/Umbraco.Core/Services/IContentCrudService.cs
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Persistence.Querying;
+
+namespace Umbraco.Cms.Core.Services;
+
+///
+/// Service for content CRUD (Create, Read, Update, Delete) operations.
+///
+///
+///
+/// Implementation Note: Do not implement this interface directly.
+/// Instead, inherit from which provides required
+/// infrastructure (scoping, repository access, auditing). Direct implementation
+/// without this base class will result in missing functionality.
+///
+///
+/// This interface is part of the ContentService refactoring initiative.
+/// It extracts core CRUD operations into a focused, testable service.
+///
+///
+/// Versioning Policy: This interface follows additive-only changes.
+/// New methods may be added with default implementations. Existing methods will not
+/// be removed or have signatures changed without a 2 major version deprecation period.
+///
+///
+/// Version History:
+///
+/// - v1.0 (Phase 1): Initial interface with Create, Read, Save, Delete operations
+///
+///
+///
+/// 1.0
+public interface IContentCrudService : IService
+{
+ #region Create
+
+ ///
+ /// Creates a document without persisting it.
+ ///
+ /// Name of the document.
+ /// Id of the parent, or -1 for root.
+ /// Alias of the content type.
+ /// Optional id of the user creating the content.
+ /// The new document.
+ IContent Create(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId);
+
+ ///
+ /// Creates a document without persisting it.
+ ///
+ /// Name of the document.
+ /// Guid key of the parent.
+ /// Alias of the content type.
+ /// Optional id of the user creating the content.
+ /// The new document.
+ IContent Create(string name, Guid parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId);
+
+ ///
+ /// Creates a document without persisting it.
+ ///
+ /// Name of the document.
+ /// Id of the parent, or -1 for root.
+ /// The content type.
+ /// Optional id of the user creating the content.
+ /// The new document.
+ IContent Create(string name, int parentId, IContentType contentType, int userId = Constants.Security.SuperUserId);
+
+ ///
+ /// Creates a document without persisting it.
+ ///
+ /// Name of the document.
+ /// The parent document.
+ /// Alias of the content type.
+ /// Optional id of the user creating the content.
+ /// The new document.
+ IContent Create(string name, IContent? parent, string contentTypeAlias, int userId = Constants.Security.SuperUserId);
+
+ ///
+ /// Creates and persists a document.
+ ///
+ /// Name of the document.
+ /// Id of the parent, or -1 for root.
+ /// Alias of the content type.
+ /// Optional id of the user creating the content.
+ /// The persisted document.
+ IContent CreateAndSave(string name, int parentId, string contentTypeAlias, int userId = Constants.Security.SuperUserId);
+
+ ///
+ /// Creates and persists a document.
+ ///
+ /// Name of the document.
+ /// The parent document.
+ /// Alias of the content type.
+ /// Optional id of the user creating the content.
+ /// The persisted document.
+ IContent CreateAndSave(string name, IContent parent, string contentTypeAlias, int userId = Constants.Security.SuperUserId);
+
+ #endregion
+
+ #region Read
+
+ ///
+ /// Gets a document by id.
+ ///
+ /// The document id.
+ /// The document, or null if not found.
+ IContent? GetById(int id);
+
+ ///
+ /// Gets a document by key.
+ ///
+ /// The document key.
+ /// The document, or null if not found.
+ IContent? GetById(Guid key);
+
+ ///
+ /// Gets documents by ids.
+ ///
+ /// The document ids.
+ /// The documents.
+ IEnumerable GetByIds(IEnumerable ids);
+
+ ///
+ /// Gets documents by keys.
+ ///
+ /// The document keys.
+ /// The documents.
+ IEnumerable GetByIds(IEnumerable ids);
+
+ ///
+ /// Gets root-level documents.
+ ///
+ /// The root documents.
+ IEnumerable GetRootContent();
+
+ ///
+ /// Gets the parent of a document.
+ ///
+ /// Id of the document.
+ /// The parent document, or null if at root.
+ IContent? GetParent(int id);
+
+ ///
+ /// Gets the parent of a document.
+ ///
+ /// The document.
+ /// The parent document, or null if at root.
+ IContent? GetParent(IContent? content);
+
+ #endregion
+
+ #region Read (Tree Traversal)
+
+ ///
+ /// Gets ancestors of a document.
+ ///
+ /// Id of the document.
+ /// The ancestor documents, from root to parent (closest to root first).
+ IEnumerable GetAncestors(int id);
+
+ ///
+ /// Gets ancestors of a document.
+ ///
+ /// The document.
+ /// The ancestor documents, from root to parent (closest to root first).
+ IEnumerable GetAncestors(IContent content);
+
+ ///
+ /// Gets paged children of a document.
+ ///
+ /// Id of the parent document.
+ /// Zero-based page index.
+ /// Page size.
+ /// Total number of children.
+ /// Optional filter query.
+ /// Optional ordering.
+ /// The child documents.
+ IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, IQuery? filter = null, Ordering? ordering = null);
+
+ ///
+ /// Gets paged descendants of a document.
+ ///
+ /// Id of the ancestor document.
+ /// Zero-based page index.
+ /// Page size.
+ /// Total number of descendants.
+ /// Optional filter query.
+ /// Optional ordering.
+ /// The descendant documents.
+ IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, IQuery? filter = null, Ordering? ordering = null);
+
+ ///
+ /// Checks whether a document has children.
+ ///
+ /// The document id.
+ /// True if the document has children; otherwise false.
+ bool HasChildren(int id);
+
+ ///
+ /// Checks whether a document with the specified id exists.
+ ///
+ /// The document id.
+ /// True if the document exists; otherwise false.
+ bool Exists(int id);
+
+ ///
+ /// Checks whether a document with the specified key exists.
+ ///
+ /// The document key.
+ /// True if the document exists; otherwise false.
+ bool Exists(Guid key);
+
+ #endregion
+
+ #region Save
+
+ ///
+ /// Saves a document.
+ ///
+ /// The document to save.
+ /// Optional id of the user saving the content.
+ /// Optional content schedule.
+ /// The operation result.
+ OperationResult Save(IContent content, int? userId = null, ContentScheduleCollection? contentSchedule = null);
+
+ ///
+ /// Saves multiple documents.
+ ///
+ /// The documents to save.
+ /// Optional id of the user saving the content.
+ /// The operation result.
+ ///
+ /// This method does not support content schedules. To save content with schedules,
+ /// use the single-item overload.
+ ///
+ OperationResult Save(IEnumerable contents, int userId = Constants.Security.SuperUserId);
+
+ #endregion
+
+ #region Delete
+
+ ///
+ /// Permanently deletes a document and all its descendants.
+ ///
+ /// The document to delete.
+ /// Optional id of the user deleting the content.
+ /// The operation result.
+ OperationResult Delete(IContent content, int userId = Constants.Security.SuperUserId);
+
+ #endregion
+}
+```
+
+**Step 2: Verify the project builds**
+
+Run: `dotnet build src/Umbraco.Core/Umbraco.Core.csproj`
+Expected: Build succeeded.
+
+**Step 3: Commit**
+
+```bash
+git add src/Umbraco.Core/Services/IContentCrudService.cs
+git commit -m "$(cat <<'EOF'
+feat(core): add IContentCrudService interface for Phase 1
+
+Defines the contract for content CRUD operations:
+- Create: 6 overloads for creating documents
+- Read: GetById, GetByIds, GetRootContent, GetParent
+- Read (Tree Traversal): GetAncestors, GetPagedChildren, GetPagedDescendants
+- Save: Single and batch save operations
+- Delete: Permanent deletion with cascade
+
+🤖 Generated with [Claude Code](https://claude.com/claude-code)
+
+Co-Authored-By: Claude
+EOF
+)"
+```
+
+---
+
+## Task 3: Create ContentCrudService Implementation
+
+**Files:**
+- Create: `src/Umbraco.Core/Services/ContentCrudService.cs`
+
+**Step 1: Write a failing unit test for ContentCrudService**
+
+Create a simple test to verify the service can be constructed:
+
+```csharp
+// tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/ContentCrudServiceTests.cs
+using Microsoft.Extensions.Logging;
+using Moq;
+using NUnit.Framework;
+using Umbraco.Cms.Core;
+using Umbraco.Cms.Core.Events;
+using Umbraco.Cms.Core.Models;
+using Umbraco.Cms.Core.Persistence.Repositories;
+using Umbraco.Cms.Core.Scoping;
+using Umbraco.Cms.Core.Services;
+using IsolationLevel = System.Data.IsolationLevel;
+
+namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Services;
+
+[TestFixture]
+[Category("UnitTest")]
+public class ContentCrudServiceTests
+{
+ private Mock _scopeProvider = null!;
+ private Mock _loggerFactory = null!;
+ private Mock _eventMessagesFactory = null!;
+ private Mock _documentRepository = null!;
+ private Mock _entityRepository = null!;
+ private Mock _contentTypeRepository = null!;
+ private Mock _auditService = null!;
+ private Mock _userIdKeyResolver = null!;
+ private Mock _languageRepository = null!;
+ private ContentCrudService _sut = null!;
+
+ [SetUp]
+ public void SetUp()
+ {
+ _scopeProvider = new Mock();
+ _loggerFactory = new Mock();
+ _eventMessagesFactory = new Mock