1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
// SPDX-License-Identifier: GPL-3.0-only
// Copyright (C) 2026 OUTRAM PARK contributors
//
// This file is part of OUTRAM PARK. See `src/lib.rs` for the full licence
// notice.
//! Verification of the compute-backend dispatch layer.
//!
//! These are verification tests, not validation: they check that the dispatch
//! layer obeys its own stated contract. No physics is involved.
use *;
/// The serial backend is available unconditionally.
///
/// **Methodology.** Assert [`ComputeBackend::Serial`] reports available and is
/// the `Default`, on whatever target and feature set this build used. Pass
/// criterion: both hold.
///
/// **Results (2026-08-12).** Both hold. This is the load-bearing guarantee
/// behind [`ComputeBackend::resolve`] never failing — if it ever broke, every
/// fallback path in the crate would have nowhere to land.
/// Resolution never yields an unavailable backend, from any starting point.
///
/// **Methodology.** For each of the three variants, call
/// [`ComputeBackend::resolve`] and assert the result reports available. This
/// is the "graceful absence of a GPU" contract: on this machine the GPU is
/// almost certainly absent, so `Gpu` must degrade rather than fail. Pass
/// criterion: every resolved backend is available.
///
/// **Results (2026-08-12).** All three resolve to an available backend. In
/// this container the probe finds no adapter, so `Gpu` degrades — which is
/// exactly the path a headless CI machine takes, and it is exercised here
/// rather than assumed.
/// A requested backend never resolves *upward* to a more capable one.
///
/// **Methodology.** `Serial` must resolve to `Serial` — asking for the oracle
/// must never silently hand back an accelerated path, because verification
/// runs depend on getting the reference implementation they asked for. Pass
/// criterion: `Serial.resolve() == Serial`.
///
/// **Results (2026-08-12).** Holds. This matters more than it looks: a V&V
/// gate that asked for `Serial` and silently got `CpuMulti` would be checking
/// the accelerated path against itself.
/// Small problems always run serially, whatever is compiled in.
///
/// **Methodology.** Call [`select_backend`] with work-item counts below
/// [`CPU_MULTI_MIN_WORK_ITEMS`] and assert it returns
/// [`ComputeBackend::Serial`]. Inputs: 0, 1, 16, and one item below the
/// threshold. Pass criterion: all four give `Serial`.
///
/// **Results (2026-08-12).** All four give `Serial`. This is the guard against
/// the classic mistake of paying thread-pool or PCIe overhead to add two
/// 50-element vectors.
/// Whatever the policy picks is runnable, at every scale.
///
/// **Methodology.** Sweep work-item counts across both thresholds and assert
/// each selection reports available. Inputs: 0 through 1e6, spanning
/// [`CPU_MULTI_MIN_WORK_ITEMS`] and [`GPU_MIN_WORK_ITEMS`]. Pass criterion:
/// every selection is available.
///
/// **Results (2026-08-12).** Every selection is available across the sweep.
/// The two thresholds are ordered, and GPU needs strictly more work than
/// multi-CPU to be worth it.
///
/// **Methodology.** Assert `CPU_MULTI_MIN_WORK_ITEMS < GPU_MIN_WORK_ITEMS`.
/// Pass criterion: strict inequality.
///
/// **Results (2026-08-12).** `4096 < 65536` holds. If this ever inverted,
/// [`select_backend`] would offer the GPU for problems too small even for
/// threads, which is the wrong way round: a GPU dispatch additionally pays a
/// host-device round trip.
/// Thread counts resolve to at least one worker, including from degenerate
/// requests.
///
/// **Methodology.** Resolve `Auto`, `Fixed(0)`, `Fixed(1)`, `Fixed(7)`, and
/// `Fraction` values including 0.0, a negative, NaN and infinity. Pass
/// criterion: every result is `>= 1`, and the exact values are as documented
/// for `Fixed`.
///
/// **Results (2026-08-12).** All resolve to `>= 1`; `Fixed(0)` clamps to 1 and
/// `Fixed(7)` gives 7. The degenerate fractions clamp to 1 rather than
/// panicking or producing 0 — a zero would be handed straight to a thread-pool
/// builder, which is exactly the sort of input that turns into a confusing
/// panic deep inside rayon.
/// The GPU probe is cached, so it cannot cost anything after the first call.
///
/// **Methodology.** Call [`gpu_adapter_present`] twice and assert the answers
/// agree. Pass criterion: identical results, and no panic on a machine with no
/// adapter.
///
/// **Results (2026-08-12).** Both calls agree. In this container the result is
/// `false` (no GPU adapter), which exercises the fallback path rather than the
/// GPU path — the GPU path itself remains unexecuted and unverified here, and
/// bead `op-b4a.4.8` already tracks validating wgpu dispatch on a real GPU
/// host for the workspace generally.
/// Backend labels are distinct, so a benchmark table cannot conflate two rows.
///
/// **Methodology.** Collect the three labels and assert all differ and none is
/// empty. Pass criterion: three distinct non-empty strings.
///
/// **Results (2026-08-12).** `serial`, `cpu-multi`, `gpu` — distinct.