How Crucible runs a model.
Two separate runtimes. The native C++17 engine (20 ONNX operators, Eigen) runs CNNs such as ResNet18 and MobileNetV2 behind the FastAPI server and is checked against ONNX Runtime. A much smaller Rust interpreter (5 operators) is compiled to WebAssembly so the fraud model can be scored in the browser. They share the approach, not the code.
Tensors are flat, row-major NCHW.
A shape like [N, C, H, W] is one contiguous float32buffer. The stride of each axis is the product of the dimensions after it — stride[i] = shape[i+1] * stride[i+1] — so an index like (n, c, h, w) maps to one offset. MatMul and Gemm view the buffer in place through Eigen::Map; Conv first unfolds receptive fields with im2col (1×1 stride-1 and depthwise convs skip that step).
shape = [1, 3, 224, 224] stride = [3*224*224, 224*224, 224, 1] offset = n*stride[0] + c*stride[1] + h*stride[2] + w*stride[3]
Execution order is Kahn's algorithm.
An ONNX graph is a DAG of operators. Crucible builds an in-degree[node] map, seeds a ready-set with every zero-in-degree node, and pops nodes off in topological order — decrementing successors, appending them when their in-degree hits zero. Deterministic, cycle-detecting, and small.
ready = { n : in_degree[n] == 0 }
while ready not empty:
n = ready.pop()
execute(n)
for m in successors(n):
if --in_degree[m] == 0: ready.add(m)