# Regression validation: quick, multigrid and full

Build the Release solution once, then run `verify-all` from the PolyCFD root.
`full` remains the default. Every selection requires explicit CUDA by default and
never silently falls back to a CPU accelerator. The same runner provides durable
reports, evidence hashes, stop-on-failure and check-boundary resume for all subsets.

## Chebyshev diffusion — 2026-09-26

SOL-02a replaced the weighted-Jacobi diffusion primary phase with Chebyshev semi-iteration on
undamped Jacobi ([Diffusion README](/src/PolyCfd.Gpu/Diffusion/README); tolerance, 400/800
budgets, colored fallback and device bytes unchanged). The final SOL-02a build (frozen as
`output/builds/sol02a` until SOL-02c removes it; the report's provenance records its assembly
hashes) passes **`verify-all --suite quick`** (`output/validation/sol02a-fix-quick/report.json`):
14/14 regression checks, 1,067 core and 613 CUDA tests without failures or skips, and the nine
scientific workloads. Its performance check against the pre-change reference
`output/validation/sol04a-quick/performance-reference.json` passes on an idle machine (idle
checks in `output/validation/sol02a-fix-idle-checks/`): median solver step of the moving fans
−62.5% (semi-Lagrangian) and −61.5% (MacCormack), backward step −3.0%, other cases +0.2 to
−5.9%; small-case elapsed increases (+12.8% to +44.9%, under a second each) stay within their
noise floors. The build before the review fix pass (`output/validation/sol02a-quick/`) gave the
same result; the fix pass changed no scenario result (identical per-step iteration counts,
bitwise-equal final fields except the cavity-sphere case's run-to-run floor). On the short
128³ fan the median diffusion count falls from 266 to 56 and final fields differ from the Jacobi
build by relative L2 about 3e-6. Free device memory does not drop over 200 repeated diffusion
or pressure solves (`output/validation/sol02a-free-memory.json`). The prescribed-flow
enclosure's four 20-step startup controls accept at cap 800 and its step-3 audit converges in
76 iterations with independent host residual 9.289e-7 (WSL; see the
[enclosure plan](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/docs/plans/prescribed-flow-enclosure.md)). The multigrid and full suites, their
performance comparisons and SOL-02b follow in the [solver seams plan](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/docs/plans/solver-seams-chebyshev.md);
until then this is quick-suite evidence only. **CPU backend not run (user directive).**

## Diffusion fallback validation — 2026-09-24

This section validated the previous weighted-Jacobi primary phase with the colored fallback;
it keeps its frozen-build binding as history.

**Full CUDA scientific checks pass; overall regression remains failed on timing
(30/31 required checks).** The report is
`output/validation/diffusion-full-verified-20260924/report.json`, bound to frozen
`output/builds/diffusion-verified-20260924` artifacts. All **1,525 selected tests**,
**25 native simulations**, the five-case channel study/replay and saved-field
regressions pass. Both full fans pass. The planar analytical velocity error is
0.8565%; the principal 128³ cavity differs from OpenFOAM by 0.6822%. All 22 nonlinear
snapshots pass regression, with maximum velocity changes 0.002690% / 0.004534% at
base/half timestep. Separate strict coarse-cavity and spectral qualifications
retain their known failed verdicts. No physical reference or limit changed.

The guarded full run took **233.104 raw-clock minutes (3 h 53 min)**, excluding the
subsequent timing control/retry. This is observed completion time under the
recorded workload, not an isolated solver-performance claim. The shared 800-sweep
cap supersedes the historical 200-sweep setting in the frozen 2026-09-19 channel
configuration; the five-case physical acceptance criteria are unchanged.

The first performance attempt failed against the unchanged historical reference.
One deliberate retry remeasured all nine scientific workloads successfully and
reused every completed long check. It still fails backward-step elapsed +32.9%,
median +25.8%, and shear-Z/planar-SL medians +25.8%, against the unchanged 20%
allowance and noise floors. Both failed attempts remain intact. A control using
the exact historical libraries and matching scientific identities also fails its
old gate (backward-step elapsed +41.8%, median +24.9%). Monitoring revealed
intermittent Windows PolyCFD workers during both timing sequences. These runs
are **not isolated timings**; do not treat them as proof of a patch-related
slowdown, a speedup, or grounds to replace a reference. Arrange a quiet Windows
test session before another deliberate timing phase. OpenFOAM and its old
200-sweep continuation remain paused until the new required gate passes.

The current solver passes its earlier matched before/after comparison:
316.324 → 288.697 s process time. Balanced isolated-kernel observations are within
about 1–2% on the two tested ordinary-path grids. Variable workstation load limits
performance conclusions. Four 20-step enclosure controls, an independent step-3
residual audit and 92 focused diffusion tests pass; these do not establish t=16
enclosure accuracy. The final GPU DLL matches the measured cleaned build.

Final repository static/CUDA verification passes **1,579 tests** (1,052 core,
481 GPU and 46 workbench CUDA), zero failures/skips, in
`output/verify/diffusion-verified-static-gpu-20260924/receipt.json`.
All 37 focused retry/resume tests pass. The initial static/fast attempt retains
workbench schema/event-stream failures; its 1,000 UI tests and build passed.
The Linux documentation-checker error was fixed and static rerun successfully.
That initial receipt is
`output/verify/diffusion-correction-static-fast-20260924/receipt.json`.
Receipt `notRun` entries distinguish the selected repository tiers from this
separate numerical suite. **CPU backend not run (user directive).**

The initial candidate's full attempt, `output/validation/diffusion-full-20260924`,
stopped at timing after 1,519 selected tests and nine scientific workloads passed;
its long cases were not run. That failure and the first completed final-build
report are preserved. All measurements, build identities, worker observations and
remaining limitations are in the [maintained diagnostic report] (unavailable local reference: `../../openfoam/compare/ENCLOSURE_N128_DIAGNOSTICS.md`)
and [machine-readable evidence] (unavailable local reference: `../../openfoam/compare/enclosure_diffusion_fix.json`).

## Post-pull integration — 2026-09-24

The requested commit integrates upstream `422be0b` (Workbench Gate B). The
measured diffusion implementation and performance-retry helper are unchanged;
upstream already includes the lifecycle assertion correction and adds output
failure coverage, so its test version was retained.

`python3 tools/verify static fast gpu --artifacts-path output/builds/diffusion-post-pull-20260924 --output output/verify/diffusion-post-pull-20260924`
passed 1,066 core, 482 GPU, 730 Workbench host and 1,010 UI tests, with no skips.
Workbench CUDA passed 53/54: `FaultMatrixTests.AKillAtEachBoundaryPreservesOutputsNeverDuplicatesDispatchAndProvesExitBeforeTheSlotReopens`
failed for `AfterStart / KillService`, asserting that a later worker launched
before the test observed the orphan exit. This worker-recovery failure is
unresolved; the failed receipt and TRX remain in that output directory.

The first UI typecheck/build failed because the pulled Playwright dependency was
not installed. After `npm ci --no-audit --no-fund` in `src/workbench-ui`,
`npm run build` passed (including typechecking), with its log retained as
`ui-build-after-install.log` in the same receipt directory. The lockfile was
unchanged. A fresh `python3 tools/verify static` using separate artifacts passes
all 11 steps in `output/verify/diffusion-post-pull-static-20260924/receipt.json`.
The aggregate first receipt remains failed; follow-up results do not erase it.

Both receipts list `verify-all` as required and not run by `tools/verify`.
The full numerical suite above belongs to the preserved pre-pull build; it was
not rerun for this integration and is not a full pass for the pulled tree.
Its unresolved performance gate remains documented. **CPU backend not run
(user directive).**

## Choose coverage for the change

| Selection | Use for | Expected duration on this RTX 3080 workstation |
| --- | --- | --- |
| `--suite quick` | Routine numerical, API, scenario, advection or diffusion changes; broad first check | **8–12 minutes**, estimate |
| `--suite multigrid` | Changes confined to MG smoothing, restriction/prolongation, hierarchy or preconditioning | **6–10 minutes**, estimate |
| `--suite full` | Shared solver/indexing/geometry changes, long-time stability, force statistics, refinement, or final broad numerical acceptance | **About 3¼–4 hours**, observed full runs; latest 3 h 53 min before timing retries |

The short-suite estimates are assembled from previous check timings, not measured
end-to-end results of these new subsets. Build time is additional. CPU/GPU load,
JIT and clock variation affect runtime. The full duration uses the preserved v5
run's two `CLOCK_MONOTONIC_RAW` storage-guard intervals (about 3 h 16 min including
its brief checkpoint/resume gap), before removing about one minute of duplicate
short simulations. OpenFOAM reference generation is separate.

For **Jacobi pressure/nullspace changes**, use quick: it includes the tight
residual regression and a 20-step 128×128×256 stationary fan through the historical
step-6 failure. For **multigrid**, the focused GPU selection includes shared PCG,
pressure, projection, BLAS, boundary/halo, div-grad, moving-wall, session and moving
workflow tests. It deliberately keeps Jacobi comparison controls. All core tests
other than the duplicate simulation wrappers also run. Selecting only classes
named `Multigrid` would miss these integration contracts. The session-level memory
audit (`InspectionPreflightTests`) sits outside the selection, but the per-solver
footprint test (`Multigrid.PressureSolverFootprintTests`) is inside it, so a multigrid
run still fails when a solver buffer changes without its owner's byte function. The pressure solver contract and
transfer-budget theories over both solver kinds (`Numerics.Pcg.PressureSolverContractTests`,
`PressureSolverResourceTests`) are inside it too.

For **shared pressure, diffusion, advection, geometry or indexing changes**, start
with quick and use full before claiming broad numerical acceptance. Both long fan
schemes remain valuable for accumulated error; do not shrink the 128³ moving-fan
grid because that changes the hub connectivity. Force-related changes need the
full cylinder statistics window. Schema/docs-only work can use its focused checks
from [AGENTS.md](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/AGENTS.md) without a solver suite. UI checks remain separate.

No automatic changed-file dependency inference is used. Membership and filters
are explicit in [SuiteCases.cs](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/validation/PolyCfd.Validation/Suites/SuiteCases.cs);
the multigrid GPU selection is pinned by a committed
[snapshot](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/test/PolyCfd.Gpu.Tests/Suites/multigrid-selection.txt) that a test
compares by reflection, so renaming a test cannot silently shrink it. Both are
protected paths for [`tools/verify`](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/test/README.md#one-command-verification),
which never runs these suites itself; when numerical code changed it prints the suite
this table suggests (multigrid for multigrid-only code, otherwise quick, then full) as
advice. Reports bind the chosen subset, filters, inputs, build and references. A
passing subset means **that subset passed**; it does not mean full validation passed.

## Commands and prerequisites

Run performance checks sequentially without competing CFD jobs. Accuracy checks
may share the machine when appropriate, but their timings do not establish a
performance result. Use a fresh output for each build/selection.

```bash
dotnet build PolyCfd.sln -c Release

dotnet src/PolyCfd.Cli/bin/Release/net10.0/PolyCfd.Cli.dll verify-all \
  --suite quick --backend cuda --output output/validation/quick \
  --performance-baseline /path/to/accepted-raw-performance.json --check-performance

dotnet src/PolyCfd.Cli/bin/Release/net10.0/PolyCfd.Cli.dll verify-all \
  --suite multigrid --backend cuda --output output/validation/multigrid \
  --performance-baseline /path/to/accepted-raw-performance.json --check-performance \
  --comparison-root ../openfoam --python ../openfoam/.venv/bin/python

dotnet src/PolyCfd.Cli/bin/Release/net10.0/PolyCfd.Cli.dll verify-all \
  --suite full --backend cuda --output output/validation/full \
  --performance-baseline /path/to/accepted-raw-performance.json --check-performance \
  --comparison-root ../openfoam --python ../openfoam/.venv/bin/python
```

Quick needs no independent OpenFOAM fields. Multigrid needs the comparison repo,
its `compare/subsets/cavity.py`, Python dependencies in `compare/requirements.txt`,
and the hash-matched `cavity-64` entry in `compare/suite_references.json`. It compares
the final field at t=10 with the original velocity/energy/profile/pressure limits;
it makes no mesh-refinement or timestep-refinement claim. Full needs the complete
reference inventory and channel protocol inputs. Missing evidence stays incomplete.

All three selections measure the **same nine performance workloads**, so the
same accepted baseline applies. On this workstation the preserved local reference
is `../openfoam/enclosure/runs/incremental-projection/before-suite/performance.json`.
It is local run data, not guaranteed in a fresh clone. References must match case
keys, clock, timing boundary, device and environment. Old stopwatch references
are incompatible and are not rescaled. The 20% allowance and noise floors are unchanged.
Without a reference, the performance check is **incomplete**; independent numerical
checks still run and the overall exit code remains 2. `--keep-going` controls
continuation after failed regression checks, not this missing-reference verdict.
Never record a new baseline merely to make a failed comparison pass. Use
`--record-performance --performance-baseline /new/path.json` only for an intentional
new reference; it never overwrites one.
See [performance scope](/docs/PERFORMANCE_VALIDATION).

To check only the selected test projects first, add `--stop-after gpu-tests`.
The rest stays pending and the exit code is 2. Continue with the identical command,
remove `--stop-after`, and add `--resume`. Changing `--suite` requires a new output;
it cannot turn a previous subset into a full pass.

### Isolated builds while another campaign owns frozen binaries

Do not rebuild over test/CLI deployments bound to a running or resumable campaign.
Use .NET's separate artifacts directory and tell the suite where its matching
test binaries are. This avoids stale test dependencies without copying deployments.

```bash
dotnet build PolyCfd.sln -c Release --artifacts-path output/builds/my-validation
dotnet output/builds/my-validation/bin/PolyCfd.Cli/release/PolyCfd.Cli.dll verify-all \
  --artifacts-path output/builds/my-validation \
  --suite quick --backend cuda --output output/validation/my-quick \
  --performance-baseline /path/to/accepted-raw-performance.json --check-performance
```

The option points to the same artifacts root used for the build. The suite runs
`bin/<test-project>/release/<test-project>.dll` and verifies production DLLs against
the executing CLI. Without it, normal `test/<project>/bin/Release/net10.0` paths apply.

## Coverage and expensive checks

| Coverage | Quick | Multigrid | Full |
| --- | --- | --- | --- |
| Core contracts and validator tests | All | All | All |
| GPU tests | All CUDA-compatible | Pressure/MG and shared integration selection | All CUDA-compatible |
| Nine scientific controls and unchanged performance gate | Yes | Yes | Yes |
| Stationary fan, original Jacobi settings and full grid | First 20 steps | Small cross-solver tests | Full 1,000 steps |
| 64³ cavity t=10 and independent final-field comparison | No | Yes | Yes |
| Poiseuille both schemes, cavity sphere, obstacle channel, cylinder force window | No | No | Yes |
| Both 128³ ten-revolution fans; planar 128³ t=20 | No | No | Yes |
| Full cavity and nonlinear Taylor–Green refinement matrices | No | No | Yes |
| Channel v2 five steady cases/replay | Startup unit test only | Startup unit test only | Yes |
| Principal cavity refinement and direct nonlinear trajectory regression | No | No | Yes |
| Strict full cavity/spectral qualification | Not requested | Not requested | Separate verdict, unchanged limits |

Eight xUnit simulation wrappers (two planar, four periodic controls, two moving
fans) have `SuiteCase=Mandatory`. `verify-all` excludes those wrappers because it
runs the same cases explicitly with their scientific checks and timing. Ordinary
`dotnet test` still runs them. Tests of rejection/validation logic remain selected.
This removes about one minute of repeated work without removing a scientific case.

The previous full report's rounded per-check times explain the main costs:

| Group | Approximate duration | Reason retained in full |
| --- | --- | --- |
| Both ten-revolution fans | 65 min | Long-time moving geometry/diffusion/advection stability |
| Cavity + nonlinear vortex matrices | 55 min | Spatial/timestep refinement and full-field trajectories; half-step runs account for about 30 min |
| Full stationary fan | 23 min | Sustained tight Jacobi convergence and cut-cell conservation |
| Cylinder force window | 16 min | Complete, settled shedding-cycle statistics |
| Both Poiseuille trajectories | 9 min | Analytical startup and wall/diffusion accuracy for both schemes |

These component times are approximate report timestamps, not isolated performance
benchmarks. Final field analysis takes only seconds and reuses simulation outputs;
removing that analysis would lose useful evidence with little saving.

The full suite means this explicit catalog, not proof of every possible physical
problem. CPU-specific backend contracts (`Backend=CPU`) are excluded for a CUDA
run and listed in report provenance. Tests run on CUDA unless
`POLYCFD_TEST_BACKEND=cpu` selects the CPU accelerator explicitly; `--backend cpu`
sets it for its test projects, and the selector exists only in test code. Test
projects run with the checked-in serial [`test/gpu.runsettings`](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/test/gpu.runsettings),
copied into each attempt and hashed into the provenance. Host metadata and
analytical calculations still execute normally. Skipped tests are reported as
incomplete rather than counted as passes. UI tests, the workbench tests and
OpenFOAM reference **generation** are outside this solver regression catalog.

The comparison checkout supplies `compare/validate_suite_accuracy.py` and the
hash-bound `compare/suite_references.json` inventory. It reads current suite HDF5
fields without duplicate exports. Required field regression checks retain the
original 64³/128³ cavity accuracy limits, 64³→128³ refinement and 128³ timestep
limits, and require decreasing 32³/64³/128³ velocity errors. Full coarse cavity
qualification remains a separate result with the original 2% limits.

For nonlinear Taylor–Green, direct 128³ before/after fields at both timesteps are
compared at t=0,2,…,20 against the preserved periodic-index-corrected production
trajectories. Every velocity L2 and kinetic-energy difference must be <=0.1%.
This bound was set before the first direct comparison; it is numerical regression
acceptance, not a continuum accuracy claim. The unchanged 2% spectral accuracy
and refinement gates still execute and retain failed results independently.

The catalog is explicit and independent of arbitrary files in `Baselines/`.
Use `baseline replay` to check a specific complete saved reference. Historical
CSV-only data remain preserved; missing settings are never inferred from folder
names or silently converted into a current reference. The separate enclosure
reference/campaign and UI tests are outside this solver regression catalog.


## Results and restart

`<output>/report.json` is written atomically before and after every check. It lists
all planned checks, their states, attempts, evidence hashes, build/dependency and
reference identities, actual device and performance results. Test fingerprints include
deployed dependencies and fixtures; generated `output/` and `TestResults/` directories
and debug symbols are excluded so a test run does not invalidate its own resume. Each attempt has its
own log and outcome; numerical runs retain their normal scenario and verification
records. `unit-tests` and `gpu-tests` retain TRX results with individual failures.
The report contains `regressionState` and `qualificationState`; each check explicitly
records `qualificationOnly`, which is bound into the resume identity. Exit codes
are 0 (all regression checks passed and all selected qualification checks attempted),
1 (regression failure), 2 (incomplete regression or pending work), and 130 (canceled).
A failed/incomplete scientific qualification stays failed/incomplete even when the
regression exit code is zero. The console prints both verdicts. A resumed report
cannot reclassify a failed regression as qualification.

The default stops at the first failed **regression check**. Qualification failures are recorded and the remaining qualification checks run. A test-project check finishes
its test run before the suite stops. Inspect the evidence before continuing.
Add `--keep-going` to continue independent checks after understood failures.
Resume with the **same command and output**, adding `--resume`; add
`--retry-failed` only when deliberately retrying failed checks. Failed attempts
remain intact. If the performance gate is retried, all nine mandatory workloads
are remeasured sequentially with their scientific checks in the new performance
attempt directory. Previously completed long checks and original timings stay
intact. A failed fresh scientific check cannot reuse an earlier passing timing.
The first performance attempt uses the original nine measurements without
duplicating them. Retry after addressing the suspected timing condition; retain
every attempt and do not repeat until a favorable sample appears. After the
remaining checks finish, add `--stop-after performance` to bound a deliberate
timing retry; completed later results remain visible and retain their verdicts.
Completed checks are reused only if the build, catalog, backend,
environment, references and artifact hashes still match. Changed binaries or
inputs require a fresh output. A lock prevents two writers sharing one output.

Resume works at check boundaries: an interrupted case/test project/study restarts
in a fresh attempt, while earlier completed checks are reused. It is not a
mid-simulation fluid-state checkpoint. Use `--stop-after performance` (or another report
check ID) for a bounded phase, then omit it when resuming; the later catalog entries
remain pending and the phase cannot report overall success. A completed test project
with skipped tests is reused with its incomplete verdict; successful tests need not
run again. Missing prerequisites and interruptions are retried. A new or changed
reference changes the suite identity and requires a new output.

On WSL, check both the Linux filesystem and `/mnt/c`. Use the comparison repo's
`run_with_storage_guard.py` to reserve backing-volume space for full runs. The
current cavity/nonlinear fields, including geometry, require about 1.655 GiB
uncompressed. Suite exports use the existing lossless shuffle/deflate level-1
writer; constant geometry compresses strongly and no field precision is changed.
Allow at least 1.1 GiB for the compressed field matrix, plus tests, manifests and logs. This is an estimate; the guard monitors
actual free space throughout execution. Bounded phases
can budget their own remaining outputs and recheck actual free space before the next
phase; do not admit the whole matrix against a smaller output estimate. The separate enclosure campaign needs its own output budget.

## Portable verification identities

The full-suite rollout found a pre-existing platform dependency: verification
hashes included the serializer's OS-specific newline, and the embedded
backward-step reference hash depended on Git checkout line endings. Hashing now
uses LF on every platform. Existing Linux identities and numerical reference
values remain unchanged. The fixture retains all original Windows hashes and
checks them independently alongside the canonical identities.

An old Windows record can be converted explicitly to a **new directory**:

```bash
dotnet src/PolyCfd.Cli/bin/Release/net10.0/PolyCfd.Cli.dll baseline convert \
  /path/to/windows-record --output /path/to/canonical-record
```

Conversion verifies the original hash before normalizing it, checks the known
independent reference fingerprint, preserves result/field bytes, records the
mapping, and leaves the source untouched. An altered identity or unrelated
reference is rejected; normal record reads accept only the canonical identity.

## Subset implementation verification — 2026-09-21

VAL-05's isolated Release build passes **682 core + 180 selected GPU tests**, no
failures or skips, using CUDA. Five comparison tests pass; the new cavity entry
point reproduces the previous 64³ field verdict (velocity L2 difference 1.30577%)
against unchanged limits. The new 20-step full-grid Jacobi fan also passes on CUDA.
Checkpoint resume reuses the three completed backend/test-project checks; later
checks remain pending and the bounded suite correctly exits 2. Quick catalog
selection and duplicate-wrapper exclusion are checked explicitly.

[Evidence and commands] (unavailable local reference: `../output/validation/validation-subsets-20260921/assessment.json`)
record the selected tests, initial corrected test-assertion failure, and preserved
comparison inputs. Core/GPU/Execution DLLs are byte-identical to CFG-01's build.
No full suite or performance gate was rerun for this orchestration change. The
checks shared the machine with OpenFOAM and do not establish new performance
numbers or measured end-to-end durations for the subsets.

The ready CLI is
`output/validation/validation-subsets-20260921/artifacts/bin/PolyCfd.Cli/release/PolyCfd.Cli.dll`;
pass `--artifacts-path output/validation/validation-subsets-20260921/artifacts`
when using it. The normal earlier deployment remains intact for the enclosure
continuation. The previous full result below belongs to its frozen build.

## Local regression result — 2026-09-21

**Full CUDA regression passes: 31/31 required checks, exit 0.** Both independent
scientific qualification checks were attempted and remain **failed** at their
original limits. Regression success does not qualify every grid or physical problem.

The completed output is
[`verify-all-regression-20260921-v5`] (unavailable local reference: `../output/validation/verify-all-regression-20260921-v5/report.json`),
using frozen Release build `verify-all-build-20260921-v4` on the RTX 3080.
The subsequent MacCormack-default update is checked separately in
[`maccormack-default-20260921`] (unavailable local reference: `../output/validation/maccormack-default-20260921/assessment.json`):
Release build, schemas and 1,097 core/GPU tests pass. It pins established suite
schemes explicitly; the full numerical/performance suite below belongs to the
preserved v4 build and was not rerun for the default-selection change. The new
CLI is in that follow-up's isolated `artifacts/bin/PolyCfd.Cli/release/` directory;
the normal prior test deployment is retained so the completed frozen suite stays
resumable. A future source rebuild uses the new defaults.

All checks have one attempt. A completed-suite `--resume` took 4.00 raw-clock
seconds and reused all 33 results without changing their identities, attempts or
artifact hashes; a real earlier checkpoint also reused the first 13 checks.
[Restart evidence] (unavailable local reference: `../output/validation/verify-all-regression-20260921-v5/completed-resume.json`)
retains the exact command. Do not rebuild over this frozen executable or modify
its bound references, test deployment or comparison scripts.

| Required coverage | Current result |
| --- | --- |
| Release build | Zero warnings/errors |
| Core and GPU tests | 682 + 413 = **1,095 passed**, zero failures or skips; CUDA selection, documented CPU-only exclusions |
| Native scientific simulations | **25/25 passed**, including nine mandatory controls, full stationary fan and cylinder force window, both ten-revolution fans, planar vortex, four cavity and three nonlinear vortex runs |
| Planar 128³ analytical trajectory to t=20 | Maximum velocity error **0.8565%**, within the original 2% limit |
| Channel v2, five cases plus replay | Pass; finest flow error **0.19869%**, spatial ratio **4.02098**, steady timestep spread **2.1233e-6** of reference flow versus 1e-5; analytical startup-order test passes |
| Principal 128³ cavity at t=10 | Velocity difference **0.6822%**, energy difference **0.0538%**, final maxDiv **5.722e-6**; 64³/128³ accuracy, fine refinement and half-timestep checks pass |
| Nonlinear trajectory regression | All 22 snapshots pass; maximum before/after velocity differences **0.00269% / 0.00456%** at base/half timestep, below the predeclared 0.1% bound |
| Nine-case performance gate | Pass against the unchanged reference, 20% allowance and existing noise floors; largest median-step increase **18.4%**, backward-step whole-case **+10.7%**, median step **+11.8%** |
| Comparison and continuation tests | 129 comparison Python tests and six continuation tests passed |

The [field regression] (unavailable local reference: `../output/validation/verify-all-regression-20260921-v5/field-regression/attempt-001/assessment.json`)
and [channel assessment] (unavailable local reference: `../output/validation/verify-all-regression-20260921-v5/channel-refinement/attempt-001/study/assessment.json`)
retain individual measurements. Strict cavity qualification still fails at 32³
(**2.6127%** velocity error) and 32³→64³ refinement (**3.0860%**), both against
2% limits. Nonlinear spectral velocity errors remain **10.0688% / 9.6864%** at
128³ base/half timestep against 2%; spatial difference is **29.8321%**, and
timestep difference **1.6731%** exceeds 0.5%. Neither reference nor these limits
was changed. These failed qualification results remain in the same report.

The substantive solver correction is small: Jacobi PCG projects its recursive
residual to zero volume-weighted mean after each update for singular pressure
boundaries, reusing the existing device operation. No new option, buffer or
production diagnostic API was added. Fixed-pressure and multigrid solves are
unchanged. The [stationary-fan guide](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/docs/STATIONARY_FAN_VALIDATION.md) records the
failure mechanism, two new tests that fail on the old solver, 24 focused passing
pressure tests and the full 1,000-step passing fan. Two matched five-step startup
pairs measured **+8.0% raw process time** and +18.9% in the existing integration
stopwatch diagnostics; these are bounded startup costs, not full-interval throughput.

Validation was simplified by removing implicit discovery of historical CSV-only
baselines, two empty skipped placeholders and noisy unit-test speed assertions.
Explicit baseline replay remains available; repeated large-grid numerical tests
and the existing performance gate retain their respective coverage. The versioned
channel protocol measures steady timestep sensitivity and analytical startup
convergence separately. Its original v1 ratio failure remains preserved.

Failed attempts are retained: v3 exposes stationary-fan step-6 nonconvergence;
v4 stops on shear-Y median timing **+20.5%** versus the unchanged 20% allowance.
Three alternating old/new repetitions of that multigrid workload all put the new
build inside the original limit and show no fix-related slowdown. The unchanged
build then passed the fresh full v5 suite. See
`output/validation/verify-all-timing-investigation-20260921/`; no baseline or
performance threshold was relaxed.

The enclosure reference campaign has resumed under the 18 GiB storage reserve.
Its replacement continuation verifies this completed report, the channel-v2
assessment and every frozen CLI dependency before launching the separate CUDA
matrix after reference qualification. The [enclosure handoff] (unavailable local reference: `../../openfoam/enclosure/README.md#restart-and-handoff`)
and [workboard](/docs/WORKBOARD) carry its current state. Enclosure qualification
and the production comparison remain incomplete.

### Preserved original combined-gate result (v2)


At completion of the original v2 attempt, all catalog entries had been attempted.
That suite was **failed**, with 27 passed, three failed and 12 incomplete checks.
No v2 simulation remained running. The 27 passed
entries comprise the CUDA backend check, performance gate and **25 scientific
simulations**. Internal numerical acceptance and independent physical accuracy
remain separate verdicts.

| Evidence | Result |
| --- | --- |
| Release solution | Build passes, zero warnings/errors |
| Final core/GPU test projects | 1,088 passed, zero failed, three existing skips |
| Focused runner/identity tests | 56 passed, included in the project counts above |
| Comparison Python suite | 122 passed |
| Full-project restart | Reused both completed test projects with one attempt each |
| Mandatory scientific controls | All nine passed |
| Additional physical cases | Both Poiseuille schemes, cavity sphere, channel obstacle, stationary fan and full refined cylinder force window passed |
| Long native cases | Both ten-revolution fans; planar 128³ to t=20; four cavity and three nonlinear Taylor–Green runs passed |
| Planar analytical trajectory | Maximum velocity error 0.856%; energy-decay error 1.651%, both within limits |
| Performance gate | Passed against unchanged pre-pressure reference: backward-step elapsed +2.8%, median step +1.4%; largest median-step increase +10.2% (short shear-Y case), within the existing 20% allowance and noise floors |
| Frozen channel study | Failed steady temporal-ratio gate: 0.44955 versus required 1.5–2.5; finest flow error 0.19869% |
| Independent cavity matrix | Failed at 32³ (2.613% velocity difference) and 32³→64³ refinement (3.086%); 64³/128³ field comparisons, 64³→128³ refinement and 128³ timestep checks pass |
| Principal 128³ cavity at t=10 | OpenFOAM velocity difference 0.6822%, kinetic energy difference 0.0538%; final maximum divergence 5.722e-6, below 1e-5 |
| Nonlinear Taylor–Green qualification | Failed: maximum spectral-reference velocity error 10.0688% at 128³, 9.6864% with half timestep; target 2% |
| Nonlinear refinement | Failed: 64³→128³ velocity difference 29.832%; 128³ timestep difference 1.673% versus 0.5% limit |
| Independent enclosure qualification | Incomplete: qualified reference fixture is absent; no new enclosure simulation launched |

The channel assessment JSON exactly matches the preserved incremental-pressure
study. It is the previously identified steady-state convergence-ratio failure,
not a newly appearing change in those measurements. See the existing
[channel assessment](https://github.com/hankbeasley/polycfd/blob/2515fae75250ee310a783c96057bc4b0a4fa9ee6/docs/DUCT_ACCURACY.md) for the small steady timestep differences
and separate transient convergence evidence. Its frozen limits remain unchanged.
The nonlinear Taylor–Green errors likewise reproduce the earlier approximately
10.07% / 9.69% results; native stability does not satisfy the stricter field limits.
Cavity energy-history interpolation uses only one-second native samples and is
not a resolved startup-trajectory validation; the accepted comparisons above use
the final full-volume fields.

The 12 incomplete check entries consist of two test projects with three existing
skips, nine legacy saved CSV configurations lacking replay inputs, and the missing
qualified enclosure reference. These are not passes. At that stage the enclosure
campaign/controller remained paused. The completed v5 regression above now
supplies the prerequisite for the replacement continuation.

Evidence is under `output/validation/verify-all-regression-20260921-v2/`
(`report.json`, `handoff.json`, per-check logs/TRX/outcomes and independent
`assessment.json` files). The frozen CLI remains under
`output/validation/verify-all-build-20260921-v2/`. Resume and postprocessing reused
all completed simulations. The channel failure stopped the numerical phase;
`--resume --keep-going` then evaluated saved cavity/Taylor–Green fields and recorded
the missing enclosure prerequisite without retrying failed studies. All failed
attempts and original references remain intact. Changed solver/analysis inputs
require a new suite identity and output; do not rebuild over the frozen evidence.

Storage cleanup removed 185 historical intermediate exports (16.063 GiB), retaining
canonical comparison snapshots, initial/final native fields and every bound
reference. Windows free space measured about 39.5 GiB immediately after that cleanup;
recheck live capacity before further runs. Continue to
reserve 18 GiB and budget new outputs separately. See the
[cleanup inventory] (unavailable local reference: `../../openfoam/compare/cleanup-20260921.json`).
