fuel-dispatch 0.20.71

Dispatch infrastructure for fuel: KernelBindingTable, per-backend registration wrappers, CompiledNode + compile_node, ExecutionPlan + compile_plan + resolve_kernel, FusedKernelRegistry, PipelinedExecutor. The layer that takes a graph and runs it against registered backends. Extracted from fuel-memory 2026-05-31.
Documentation
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
---
fkc_version: 1
provider:
  name: fuel-cpu-backend
  backend: Cpu                       # maps to BackendId::Cpu
  kernel_source: "portable-cpu"      # the BindingEntry.kernel_source tag
  link_registry: fuel_cpu_backend::byte_kernels::ENTRY_POINTS   # §12.6 symbol→KernelRef map
  revision_base: "git:f41137b4"      # provider build id, folded into kernel_revision_hash
---

# fuel-cpu-backend — 2D convolution kernel contracts

Direct (non-im2col) 2D convolution and 2D transposed convolution for the portable `CpuStorageBytes`
surface. Two logical ops — `OpKind::Conv2D` and `OpKind::ConvTranspose2D` — each monomorphized over
the four float dtypes `{F32, F64, BF16, F16}`, for eight distinct registered kernels (distinct
`entry_point` → `KernelRef`). Each op shares one accept/return shape across its dtypes but differs in
element width and the accumulation/narrowing rule: f32/f64 accumulate natively, bf16/f16 accumulate
in **f32** and narrow on store (the family precision invariant). All eight are primitive `op_kind`
contracts (convolution is **not** a fused op — `OpParams::Conv2D` / `OpParams::ConvTranspose2D`,
`fuel-dispatch/src/kernel.rs:222` / `:244`; `OpKind::Conv2D` / `OpKind::ConvTranspose2D`,
`fuel-ir/src/dispatch.rs:122` / `:127`).

Sources: `conv2d_f32` is hand-written (`fuel-cpu-backend/src/byte_kernels.rs:7162`); `conv2d_f64` is
the native macro `conv2d_native_kernel!` (`:4380`); `conv2d_bf16` / `conv2d_f16` are the
`conv2d_half_kernel!` macro (`:4384`, instantiated `:4476-4477`). `conv_transpose2d_f32` /
`conv_transpose2d_f64` are `conv_transpose2d_native_kernel!` (`:4499`, instantiated `:4606-4607`);
`conv_transpose2d_bf16` / `conv_transpose2d_f16` are `conv_transpose2d_half_kernel!` (`:4612`,
instantiated `:4724-4725`).

These kernels are the production `CpuStorageBytes` path the dispatch wrapper
(`fuel_dispatch::dispatch::cpu_wrappers`) extracts and calls; they consume flat contiguous,
zero-offset, row-major NCHW slices and the explicit `(x_shape, w_shape, out_shape, stride, padding,
[output_padding,] dilation, groups)` geometry, never a `Layout`/strides/offset. The shared accept
surface is three inputs — `x [N, Cin, H_in, W_in]`, `weight`, and an **optional** `bias [Cout]` — and
one output `out [N, Cout, H_out, W_out]`; the spatial geometry (H_out/W_out, stride/padding/dilation,
groups, and for the transpose `output_padding`) flows entirely through the op-params, not through any
tensor layout. Group/channel divisibility (`groups != 0`, `Cin % groups == 0`, `Cout % groups == 0`,
and the weight's per-group channel slot) is build/run-validated, returning `Result` (never a panic on
the production path). The output buffer is caller-preallocated to the exact byte size and is seeded
with the broadcast bias (or zero) before accumulation.

## conv2d_f32  (2D convolution, f32 native, direct NCHW)

Direct 2D cross-correlation. For each output position `out[b, co, oh, ow]` the kernel sums
`weight[co, ci, kh_i, kw_i] · x[b, ci_offset + ci, in_h, in_w]` over the input channels of the
output's group and the `Kh × Kw` kernel window, where `in_h = oh·sh + kh_i·dh − ph`,
`in_w = ow·sw + kw_i·dw − pw`; receptive-field positions that fall outside `[0, H_in) × [0, W_in)`
(the zero-padding region) are skipped, so padding is implicit (no materialized padded input). The
accumulator is seeded with `bias[co]` (or `0` when bias is absent) and the result written once
(`byte_kernels.rs:7256-7288`). Weight layout is `[Cout, Cin/groups, Kh, Kw]`; grouped convolution is
handled by mapping each output channel to its group (`group = co / cout_per_group`) and offsetting the
input-channel base (`ci_offset = group · cin_per_group`); depthwise is the `groups == Cin`,
`Cout = Cin` special case. Arithmetic is native f32 throughout. The kernel is a pure positional nested
walk over contiguous, zero-offset, row-major NCHW buffers; it reads `x`/`weight`/optional `bias` and
fully overwrites the caller-preallocated `out`. Validation is byte-length checks against the declared
shapes (saturating, to avoid overflow on adversarial dims) plus the group/channel divisibility
contract (`:7178-7241`), returning `Result`, never a panic on the production path. Known limitations:
contiguous zero-offset NCHW only (any strided/broadcast/offset `x` or `weight` must be contiguized by
the planner first); no in-place; H_out/W_out are not recomputed — the kernel trusts the
`out_shape` it is handed (the graph builder derives the conv geometry); no im2col/Winograd fast path
(naive direct loop).

```fkc
kernel: conv2d_f32
op_kind: Conv2D
blurb: "Direct 2D convolution (cross-correlation), f32 native; x[N,Cin,H,W], weight[Cout,Cin/groups,Kh,Kw], optional bias[Cout], grouped/depthwise."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv2d_f32"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4                              # [N, Cin, H_in, W_in] NCHW
    - name: weight
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4                              # [Cout, Cin/groups, Kh, Kw]
      shape_constraint: "divisible(x.dim[1], weight.dim[1]); weight.dim[1] == x.dim[1] / groups"
    - name: bias
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1                              # [Cout]; broadcast over N×H_out×W_out by the kernel (NOT a stride-0 view)
      shape_constraint: "weight.dim[0] == bias.dim[0]"   # Cout
      optional: true                       # absent ⇒ accumulator seeded with 0
  op_params:
    variant: Conv2D                        # OpParams::Conv2D (primitive namespace; §3.7)
    fields:
      x_shape:   { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:   { kind: "[usize; 4]", note: "[Cout, Cin/groups, Kh, Kw]" }
      out_shape: { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]; kernel trusts this geometry" }
      stride:    { kind: "(usize, usize)" }
      padding:   { kind: "(usize, usize)" }
      dilation:  { kind: "(usize, usize)" }
      groups:    { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv2d(params)           # [N, Cout, H_out, W_out] from OpParams::Conv2D geometry (§5.2)
      layout_guarantee: contiguous
      aliasing: none                       # fresh preallocated buffer; bias/zero-seeded then accumulated

caps:
  awkward_layout_strategy: requires_contiguous   # ← planner inserts Op::Contiguize (itself an FKC kernel) + sums its cost
  fast_paths:
    - { when: "groups == 1", class: conv }         # dense (non-grouped) convolution
    - { when: "depthwise", note: "groups == Cin, Cout == Cin special case" }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 32

cost:
  provenance: judge_measured             # Judge bootstraps/refines (§4.4); the formula hint below is the derivable prior
  class: conv
  # FLOPs derivable: 2 MACs-as-2-flops per (output element × in-channels-per-group × Kh × Kw); this is
  # the dense upper bound (the padding skip only reduces it at the borders). out_n = N·Cout·H_out·W_out.
  flops: "2 * out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (x_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic positional nested loop; native f32 arithmetic, fixed accumulation order
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "native f32 direct conv; fixed reduction order over (Cin/group, Kh, Kw); deterministic; not bit-stable cross-hardware (FMA contraction may differ). [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv2d_f64  (2D convolution, f64 native, direct NCHW)

Identical algorithm, weight layout, grouping, padding-skip, and bias-seed semantics to `conv2d_f32`,
evaluated in native f64 throughout (`conv2d_native_kernel!`, `byte_kernels.rs:4380`). Same NCHW
contiguous zero-offset row-major byte-length validation (now against an 8-byte element) and the same
group/channel divisibility contract; same single full overwrite of a fresh preallocated `out` seeded
with `bias[co]` (or `0`). f64 gives the widest precision of the family (no widen/narrow round-trip).
Limitations match `conv2d_f32`: contiguous zero-offset NCHW only, no in-place, naive direct loop.

```fkc
kernel: conv2d_f64
op_kind: Conv2D
blurb: "Direct 2D convolution (cross-correlation), f64 native; x[N,Cin,H,W], weight[Cout,Cin/groups,Kh,Kw], optional bias[Cout], grouped/depthwise."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv2d_f64"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "divisible(x.dim[1], weight.dim[1]); weight.dim[1] == x.dim[1] / groups"
    - name: bias
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "weight.dim[0] == bias.dim[0]"
      optional: true
  op_params:
    variant: Conv2D
    fields:
      x_shape:   { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:   { kind: "[usize; 4]", note: "[Cout, Cin/groups, Kh, Kw]" }
      out_shape: { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:    { kind: "(usize, usize)" }
      padding:   { kind: "(usize, usize)" }
      dilation:  { kind: "(usize, usize)" }
      groups:    { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
    - { when: "depthwise", note: "groups == Cin, Cout == Cin special case" }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 64

cost:
  provenance: judge_measured
  class: conv
  flops: "2 * out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (x_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "native f64 direct conv; fixed reduction order; deterministic; widest precision of the family (no widen/narrow round-trip). [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv2d_bf16  (2D convolution, bf16 I/O with f32 accumulator, direct NCHW)

The `conv2d_half_kernel!`-instantiated bf16 kernel (`byte_kernels.rs:4476`, macro at `:4384`). Same
direct algorithm, NCHW weight layout, grouping, padding-skip, and overwrite semantics as
`conv2d_f32`, but **bf16 in/out with an f32 accumulator**: the per-output accumulator is seeded with
`bias[co].to_f32()` (or `0`), each `weight·x` product widens both operands via `.to_f32()` and
accumulates in f32 over the `(Cin/group, Kh, Kw)` receptive field, then `<bf16>::from_f32(acc)`
narrows once on store (`:4446-4466`). This is the family's load-bearing precision invariant: each
output position's full reduction is computed in f32, only the final stored value is bf16. Element
width is 2 bytes (`:4414-4423`). Limitations match the family: contiguous zero-offset NCHW only, no
in-place, naive direct loop.

```fkc
kernel: conv2d_bf16
op_kind: Conv2D
blurb: "Direct 2D convolution (cross-correlation), bf16 I/O with f32 accumulator; x[N,Cin,H,W], weight[Cout,Cin/groups,Kh,Kw], optional bias[Cout], grouped/depthwise."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv2d_bf16"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "divisible(x.dim[1], weight.dim[1]); weight.dim[1] == x.dim[1] / groups"
    - name: bias
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "weight.dim[0] == bias.dim[0]"
      optional: true
  op_params:
    variant: Conv2D
    fields:
      x_shape:   { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:   { kind: "[usize; 4]", note: "[Cout, Cin/groups, Kh, Kw]" }
      out_shape: { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:    { kind: "(usize, usize)" }
      padding:   { kind: "(usize, usize)" }
      dilation:  { kind: "(usize, usize)" }
      groups:    { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
    - { when: "depthwise", note: "groups == Cin, Cout == Cin special case" }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 16

cost:
  provenance: judge_measured
  class: conv
  flops: "2 * out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (x_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic loop; f32 accumulator per output position, bf16 narrow on store
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "per-output-position reduction accumulated in f32 (widen on load, narrow on store); bf16 I/O. Deterministic; not bit-stable cross-hardware. [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv2d_f16  (2D convolution, f16 I/O with f32 accumulator, direct NCHW)

The `conv2d_half_kernel!`-instantiated f16 kernel (`byte_kernels.rs:4477`, macro at `:4384`).
Byte-for-byte the same code path as `conv2d_bf16` with `half::f16` substituted for `half::bf16`:
direct conv, per-output f32 accumulator round-trip (`.to_f32()` widen on each product,
`<f16>::from_f32(acc)` narrow once on store, `:4446-4466`), same NCHW weight layout, grouping,
padding-skip, geometry/validation/overwrite, 2-byte element width. Differs from bf16 only in the IEEE
half-precision storage format (10-bit mantissa vs bf16's 7-bit, narrower exponent range).
Limitations match the family: contiguous zero-offset NCHW only, no in-place, naive direct loop.

```fkc
kernel: conv2d_f16
op_kind: Conv2D
blurb: "Direct 2D convolution (cross-correlation), f16 I/O with f32 accumulator; x[N,Cin,H,W], weight[Cout,Cin/groups,Kh,Kw], optional bias[Cout], grouped/depthwise."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv2d_f16"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "divisible(x.dim[1], weight.dim[1]); weight.dim[1] == x.dim[1] / groups"
    - name: bias
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "weight.dim[0] == bias.dim[0]"
      optional: true
  op_params:
    variant: Conv2D
    fields:
      x_shape:   { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:   { kind: "[usize; 4]", note: "[Cout, Cin/groups, Kh, Kw]" }
      out_shape: { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:    { kind: "(usize, usize)" }
      padding:   { kind: "(usize, usize)" }
      dilation:  { kind: "(usize, usize)" }
      groups:    { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
    - { when: "depthwise", note: "groups == Cin, Cout == Cin special case" }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 16

cost:
  provenance: judge_measured
  class: conv
  flops: "2 * out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (x_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic loop; f32 accumulator per output position, f16 narrow on store
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "per-output-position reduction accumulated in f32 (widen on load, narrow on store); f16 I/O (IEEE half). Deterministic; not bit-stable cross-hardware. [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv_transpose2d_f32  (2D transposed convolution, f32 native, scatter-accumulate NCHW)

Direct 2D transposed convolution (the gradient-of-convolution / fractionally-strided conv). Unlike
forward conv's per-output gather, this kernel **scatters**: the output is first seeded with the
broadcast bias `bias[co]` (or `0`), then for every input element `x[n, ci, hi, wi]` its kernel-shaped
contribution `x · weight[ci, co_local, kh_i, kw_i]` is accumulated into the output positions
`oh = hi·sh + kh_i·dh − ph`, `ow = wi·sw + kw_i·dw − pw` that land inside `[0, H_out) × [0, W_out)`
(`byte_kernels.rs:4556-4600`). The weight layout is **transposed channel order vs forward conv** —
`[Cin, Cout/groups, Kh, Kw]` (`:4516`) — and grouping splits both Cin and Cout into `groups` blocks
(`cin_per_group = Cin/groups`, `cout_per_group = Cout/groups`). A micro-optimization skips the inner
scatter when the input value is exactly zero (`val == 0`, `:4579`); this is value-data-dependent but
result-identical. Arithmetic is native f32 throughout, accumulating directly into the output buffer.
The `output_padding` op-param disambiguates the output spatial size
(`H_out = (H_in−1)·sh − 2·ph + dh·(Kh−1) + out_pad.0 + 1`) but the kernel trusts the `out_shape` it is
handed. Validation is byte-length checks against the declared shapes plus the transpose-specific
divisibility contract (`Cin == weight.dim[0]`, `Cout/groups == cout_per_group`, `groups != 0`,
`Cin % groups == 0`, `Cout % groups == 0`; `:4518-4548`), returning `Result`, never a panic. Known
limitations: contiguous zero-offset NCHW only; no in-place; H_out/W_out not recomputed (the kernel
trusts `out_shape`); naive direct scatter loop (no im2col/col2im).

```fkc
kernel: conv_transpose2d_f32
op_kind: ConvTranspose2D
blurb: "Direct 2D transposed convolution (scatter-accumulate), f32 native; x[N,Cin,H,W], weight[Cin,Cout/groups,Kh,Kw], optional bias[Cout], grouped."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv_transpose2d_f32"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4                              # [N, Cin, H_in, W_in] NCHW
    - name: weight
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4                              # [Cin, Cout/groups, Kh, Kw] (transposed channel order vs Conv2D)
      shape_constraint: "weight.dim[0] == x.dim[1]"   # weight Cin axis == input Cin
    - name: bias
      dtypes: [F32]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1                              # [Cout]; broadcast over N×H_out×W_out by the kernel (NOT a stride-0 view)
      shape_constraint: "out.dim[1] == bias.dim[0]"   # Cout
      optional: true                       # absent ⇒ output seeded with 0
  op_params:
    variant: ConvTranspose2D               # OpParams::ConvTranspose2D (primitive namespace; §3.7)
    fields:
      x_shape:        { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:        { kind: "[usize; 4]", note: "[Cin, Cout/groups, Kh, Kw]" }
      out_shape:      { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]; kernel trusts this geometry" }
      stride:         { kind: "(usize, usize)" }
      padding:        { kind: "(usize, usize)" }
      output_padding: { kind: "(usize, usize)", note: "disambiguates H_out/W_out; transpose-only param" }
      dilation:       { kind: "(usize, usize)" }
      groups:         { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv_transpose2d(params) # [N, Cout, H_out, W_out] from OpParams::ConvTranspose2D geometry (§5.2)
      layout_guarantee: contiguous
      aliasing: none                       # fresh preallocated buffer; bias/zero-seeded then scatter-accumulated

caps:
  awkward_layout_strategy: requires_contiguous   # ← planner inserts Op::Contiguize (itself an FKC kernel) + sums its cost
  fast_paths:
    - { when: "groups == 1", class: conv }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 32

cost:
  provenance: judge_measured             # Judge bootstraps/refines (§4.4); the formula hint below is the derivable prior
  class: conv
  # FLOPs derivable: transposed conv scatters from EVERY input element across the kernel window into
  # Cout/group output channels => 2 flops per (input element × Cout/group × Kh × Kw); dense upper bound
  # (border scatters that fall outside the output, and the val==0 skip, only reduce it). in_n = N·Cin·H_in·W_in.
  flops: "2 * x_shape[0] * x_shape[1] * x_shape[2] * x_shape[3] * (out_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic scatter order; native f32 arithmetic accumulated into the output buffer
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "native f32 scatter-accumulate; fixed scatter order; val==0 skip is value-dependent but result-identical; deterministic; not bit-stable cross-hardware (FMA contraction may differ). [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv_transpose2d_f64  (2D transposed convolution, f64 native, scatter-accumulate NCHW)

Identical algorithm, transposed `[Cin, Cout/groups, Kh, Kw]` weight layout, grouping, scatter-mapping,
`val == 0` skip, and bias-seed semantics to `conv_transpose2d_f32`, evaluated in native f64 throughout
(`conv_transpose2d_native_kernel!`, `byte_kernels.rs:4607`). Same NCHW contiguous zero-offset row-major
byte-length validation (now against an 8-byte element) and the same transpose divisibility contract;
same accumulation directly into the output buffer. f64 gives the widest precision of the family (no
widen/narrow round-trip). Limitations match `conv_transpose2d_f32`: contiguous zero-offset NCHW only,
no in-place, naive direct scatter loop.

```fkc
kernel: conv_transpose2d_f64
op_kind: ConvTranspose2D
blurb: "Direct 2D transposed convolution (scatter-accumulate), f64 native; x[N,Cin,H,W], weight[Cin,Cout/groups,Kh,Kw], optional bias[Cout], grouped."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv_transpose2d_f64"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "weight.dim[0] == x.dim[1]"
    - name: bias
      dtypes: [F64]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "out.dim[1] == bias.dim[0]"
      optional: true
  op_params:
    variant: ConvTranspose2D
    fields:
      x_shape:        { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:        { kind: "[usize; 4]", note: "[Cin, Cout/groups, Kh, Kw]" }
      out_shape:      { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:         { kind: "(usize, usize)" }
      padding:        { kind: "(usize, usize)" }
      output_padding: { kind: "(usize, usize)", note: "disambiguates H_out/W_out; transpose-only param" }
      dilation:       { kind: "(usize, usize)" }
      groups:         { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv_transpose2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 64

cost:
  provenance: judge_measured
  class: conv
  flops: "2 * x_shape[0] * x_shape[1] * x_shape[2] * x_shape[3] * (out_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * dtype_bytes", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "native f64 scatter-accumulate; fixed scatter order; val==0 skip value-dependent but result-identical; deterministic; widest precision of the family (no widen/narrow round-trip). [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv_transpose2d_bf16  (2D transposed convolution, bf16 I/O with f32 accumulator, scatter-accumulate NCHW)

The `conv_transpose2d_half_kernel!`-instantiated bf16 kernel (`byte_kernels.rs:4724`, macro at
`:4612`). Same scatter algorithm, transposed `[Cin, Cout/groups, Kh, Kw]` weight layout, grouping,
scatter-mapping, and `val == 0` skip as `conv_transpose2d_f32`, but **bf16 in/out with an f32
accumulator buffer**: a parallel `Vec<f32>` of the full output size is allocated, seeded with
`bias[co].to_f32()` (or `0`), every input element's contribution is widened via `.to_f32()` and
scatter-accumulated into that f32 buffer, and finally `<bf16>::from_f32(...)` narrows the whole buffer
into `out` (`:4669-4718`). This is the family precision invariant: all scatter accumulation happens in
f32, only the final stored values are bf16. Note the half path therefore allocates a transient
host-side f32 scratch buffer of `N·Cout·H_out·W_out` f32 elements (the native f32/f64 paths accumulate
in place and allocate none). Element width is 2 bytes. Limitations match the family: contiguous
zero-offset NCHW only, no in-place, naive direct scatter loop.

```fkc
kernel: conv_transpose2d_bf16
op_kind: ConvTranspose2D
blurb: "Direct 2D transposed convolution (scatter-accumulate), bf16 I/O with f32 accumulator; x[N,Cin,H,W], weight[Cin,Cout/groups,Kh,Kw], optional bias[Cout], grouped."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv_transpose2d_bf16"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "weight.dim[0] == x.dim[1]"
    - name: bias
      dtypes: [BF16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "out.dim[1] == bias.dim[0]"
      optional: true
  op_params:
    variant: ConvTranspose2D
    fields:
      x_shape:        { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:        { kind: "[usize; 4]", note: "[Cin, Cout/groups, Kh, Kw]" }
      out_shape:      { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:         { kind: "(usize, usize)" }
      padding:        { kind: "(usize, usize)" }
      output_padding: { kind: "(usize, usize)", note: "disambiguates H_out/W_out; transpose-only param" }
      dilation:       { kind: "(usize, usize)" }
      groups:         { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv_transpose2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 16

cost:
  provenance: judge_measured             # Judge bootstraps/refines (§4.4); formula hints below are the derivable prior
  class: conv
  flops: "2 * x_shape[0] * x_shape[1] * x_shape[2] * x_shape[3] * (out_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  # half path allocates a transient f32 accumulator of the full output size (host scratch); native paths allocate none.
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (dtype_bytes + 4)", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic scatter order; f32 accumulator buffer, bf16 narrow on store
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "all scatter accumulation in an f32 buffer (widen on load, narrow on store); bf16 I/O. Deterministic; not bit-stable cross-hardware. [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```

## conv_transpose2d_f16  (2D transposed convolution, f16 I/O with f32 accumulator, scatter-accumulate NCHW)

The `conv_transpose2d_half_kernel!`-instantiated f16 kernel (`byte_kernels.rs:4725`, macro at
`:4612`). Byte-for-byte the same code path as `conv_transpose2d_bf16` with `half::f16` substituted for
`half::bf16`: scatter-accumulate into a parallel `Vec<f32>` buffer seeded with `bias.to_f32()` (or
`0`), `.to_f32()` widen on each product, `<f16>::from_f32(...)` narrow the whole buffer once on store
(`:4669-4718`); same transposed `[Cin, Cout/groups, Kh, Kw]` weight layout, grouping, scatter-mapping,
`val == 0` skip, geometry/validation/overwrite, 2-byte element width, and transient f32 scratch of the
full output size. Differs from bf16 only in the IEEE half-precision storage format (10-bit mantissa vs
bf16's 7-bit, narrower exponent range). Limitations match the family: contiguous zero-offset NCHW only,
no in-place, naive direct scatter loop.

```fkc
kernel: conv_transpose2d_f16
op_kind: ConvTranspose2D
blurb: "Direct 2D transposed convolution (scatter-accumulate), f16 I/O with f32 accumulator; x[N,Cin,H,W], weight[Cin,Cout/groups,Kh,Kw], optional bias[Cout], grouped."
backend: Cpu
kernel_source: "portable-cpu"
entry_point: "fuel_cpu_backend::byte_kernels::conv_transpose2d_f16"
kernel_revision_hash: auto

accept:
  inputs:
    - name: x
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
    - name: weight
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 4
      shape_constraint: "weight.dim[0] == x.dim[1]"
    - name: bias
      dtypes: [F16]
      layout: { contiguous: required, strided: rejected, broadcast_stride0: rejected, start_offset: rejected, reverse_strides: rejected }
      rank: 1
      shape_constraint: "out.dim[1] == bias.dim[0]"
      optional: true
  op_params:
    variant: ConvTranspose2D
    fields:
      x_shape:        { kind: "[usize; 4]", note: "[N, Cin, H_in, W_in]" }
      w_shape:        { kind: "[usize; 4]", note: "[Cin, Cout/groups, Kh, Kw]" }
      out_shape:      { kind: "[usize; 4]", note: "[N, Cout, H_out, W_out]" }
      stride:         { kind: "(usize, usize)" }
      padding:        { kind: "(usize, usize)" }
      output_padding: { kind: "(usize, usize)", note: "disambiguates H_out/W_out; transpose-only param" }
      dilation:       { kind: "(usize, usize)" }
      groups:         { kind: usize, constraint: "groups != 0; Cin % groups == 0; Cout % groups == 0" }

return:
  outputs:
    - name: out
      dtype_rule: passthrough(x)
      shape_rule: conv_transpose2d(params)
      layout_guarantee: contiguous
      aliasing: none

caps:
  awkward_layout_strategy: requires_contiguous
  fast_paths:
    - { when: "groups == 1", class: conv }
  in_place: false
  alignment_bytes: 64
  access_granularity_bits: 16

cost:
  provenance: judge_measured
  class: conv
  flops: "2 * x_shape[0] * x_shape[1] * x_shape[2] * x_shape[3] * (out_shape[1] / groups) * w_shape[2] * w_shape[3]"
  bytes_moved: "(x_shape[0]*x_shape[1]*x_shape[2]*x_shape[3] + w_shape[0]*w_shape[1]*w_shape[2]*w_shape[3] + out_shape[0]*out_shape[1]*out_shape[2]*out_shape[3]) * dtype_bytes"
  memory: { device_bytes: 0, host_bytes: "out_shape[0] * out_shape[1] * out_shape[2] * out_shape[3] * (dtype_bytes + 4)", disk_bytes: 0 }

precision:
  bit_stable_on_same_hardware: true      # deterministic scatter order; f32 accumulator buffer, f16 narrow on store
  max_ulp: ~
  max_relative: ~
  max_absolute: ~
  audited: true
  notes: "all scatter accumulation in an f32 buffer (widen on load, narrow on store); f16 I/O (IEEE half). Deterministic; not bit-stable cross-hardware. [evidence: bit_stable_on_same_hardware earned EMPIRICALLY per registered dtype — 16 byte-identical repeat invocations of ONE probe, on the recording hardware and under the pinned toolchain (rust-toolchain.toml channel = 1.98.0). Not a source-level determinism argument, and not evidence about other inputs, OTHER PARAMETER CONFIGURATIONS (one probe fixes one; branches such as causal/softcap/window go untaken), other machines, or other compilers.]"

determinism: same_hardware_bitwise
```