Skip to main content

Module fkc

Module fkc 

Source
Expand description

§FKC kernel-contract importer (fkc)

The Fuel Kernel Contract (FKC) importer: parse a provider’s markdown contract file(s) and (eventually) auto-register every described kernel onto Fuel’s dispatch surface (KernelBindingTable / FusedKernelRegistry) with zero hand-written registration glue.

This module is unconditional production infrastructure (pub mod fkc in lib.rs, no feature gate; the fkc feature was removed in bd757464).

§Status — first slice

Implemented here: the module skeleton, the FkcError type, the serde schema structs mirroring FKC §3.1 / §3.2 / §3.3, and the markdown + restricted-YAML parser (parse_file / parse_path) that:

  • splits the file-level --- front-matter (§3.1),
  • extracts each ## section’s single ```fkc block (§3.1),
  • enforces the §3.8 restricted YAML subset (tabs / anchors / aliases / merge keys / the Norway problem) BEFORE deserializing, then
  • deserializes each block into the schema and assembles an FkcFile.

Also implemented: lowering to dispatch types (lower.rs), caps/cost/ precision projection, the LinkRegistry, the revision hash, and — this slice — the END-TO-END registration path (register.rs): import_bundle_str / import_bundle / import_glob → ImportedProvider → ImportedProvider::register_into populating both the KernelBindingTable (primitives) and the FusedKernelRegistry (fused ops), with the duplicate-detection finalize gate surfaced as FkcError::DuplicateKernelRef.

NOT yet implemented (later slices of the plan): the cost trampoline / global cost-table (imported costs use the Judge-bootstrapped sentinel CostFn for now), the full V-FKC-* validators, and the CI lint.

§Authoritative references

  • Format spec: docs/specs/kernel-contract-format.md.
  • Adoption plan: docs/session-prompts/kernel-contract-adoption-plan.md.
  • Authored corpus (valid instances): fuel-dispatch/kernel-contracts/**/*.fkc.md.

Modules§

shape_expr
Fuel’s independent typed shape-expression AST + §6.19 canonical wire codec + evaluator (KISS-Ops §6.20). Byte-matches the KISS reference (conformance/src/shape_expr.rs), verified against the vendored golden vectors — the shape-side companion to the value oracle. EXPRESSION kind only (SameAs + DimExpr); the role/index-woven kind (reduce/gather/matmul) is a separate variant (Convergence-C C-2). Every malformed input is a typed decline, never a panic.

Structs§

AcceptBlock
The accept: block.
CapsBlock
Capability block (§4.1–§4.6).
CostBlock
Cost block (§4.4). Coefficient EXPRESSION fields stay String — FKC’s own parser reads them later, NOT YAML. ~ (YAML null) deserializes to None.
CostEvalError
An eval failure (an undefined symbol, or division by zero).
CostMemory
Per-tier memory footprint (§4.4). Each tier is an expression String (or a literal 0); kept as a raw scalar so 0 and "n * 4" both parse.
CpuLinkRegistry
The built-in CPU backend’s LinkRegistry — resolves a contract’s entry_point symbols against CPU_BINARY_ENTRY_POINTS, CPU_AFFINE_CLAMP_POWI_ENTRY_POINTS, CPU_UNARY_ENTRY_POINTS, CPU_COMPARE_ENTRY_POINTS, CPU_WHERE_ENTRY_POINTS, CPU_REDUCE_ENTRY_POINTS, CPU_REDUCE_TO_ENTRY_POINTS, CPU_NORM_ENTRY_POINTS, CPU_NORM_BACKWARD_ENTRY_POINTS, CPU_ROPE_ENTRY_POINTS, CPU_SSM_ENTRY_POINTS, CPU_CONV_ENTRY_POINTS, CPU_PADDING_ENTRY_POINTS, CPU_SHAPE_OPS_ENTRY_POINTS, CPU_INDEXING_ENTRY_POINTS, CPU_MATMUL_ENTRY_POINTS, CPU_ATTENTION_ENTRY_POINTS, CPU_INPLACE_ENTRY_POINTS, and CPU_CAST_ENTRY_POINTS. Unresolved → None, which the importer turns into a typed UnknownEntryPoint error (never a panic, never a fabricated pointer).
FdxSpec
DLPack-extension (FDX) requirements on an operand (§3.2 fdx:).
FkcFile
A fully parsed FKC file: front-matter + one record per ## kernel section.
FkcFrontMatter
The file-level ----fenced YAML front-matter (§3.1).
FkcKernel
The per-kernel ```fkc structured contract (§3.3).
FkcProvider
Provider identity (front-matter provider: mapping, §3.1).
GatherSpec
Paged / indexed-residency (gather) operand spec (§3.9.1).
ImportWarning
A single non-fatal FKC import diagnostic.
ImportedProvider
A parsed + validated provider bundle, holding the resolved per-kernel records ready to register. Construction (import_*) already ran the parse + restricted-YAML pre-pass + lowering (string → typed dispatch records); Self::register_into only does the registry inserts + the duplicate-detection gate.
LayoutSpec
The five-flag layout capability set (§4.1). Each flag is a string tri-state (required/accepted/n/a for contiguous; accepted/rejected for the rest) carried verbatim — projection onto today’s KernelCaps.strided_input is a lowering concern (§6).
OpParamFieldSpec
A single op-param field spec ({ kind, constraint?, note? }, §3.7).
OpParamsSchema
Op-param schema (§3.7): names the params variant + per-field constraints.
OutputDesc
An output descriptor + return rules (§5.1–§5.4). Rule fields are String expressions parsed by FKC later, not YAML.
PrecisionBlock
Precision block (§4.8) → PrecisionGuarantee. Bound fields are raw scalars (0, a float, or ~); the typed conversion is a lowering concern.
QuantSpec
Quant facts (§3.2 fdx.quant:). All tokens are String (disarms Norway; the typed conversion is a lowering concern).
ResolvedFused
A fully-lowered fused (fused_op) contract — analogous to ResolvedPrimitive but targeting the FusedKernelRegistry (FusedOpId instead of OpKind; the fused cost target).
ResolvedLayout
The full typed five-flag layout set for one operand — every flag retained, even the ones not yet projected onto KernelCaps (§6 [consumer-ahead]).
ResolvedPrimitive
A fully-lowered primitive (op_kind) contract — typed dispatch record ready for the register slice. The cost is held as a parsed AST (CompiledCostExpr), NOT a CostFn fn-pointer (the trampoline is the next slice).
ReturnBlock
The return: block.
ShapeConstraint
TensorDesc
A tensor descriptor (operand or, with return rules, an output; §3.2).

Enums§

AxisIndex
CompiledCostExpr
A compiled cost-expression AST (FKC §4.4 / §2.3 strategy A).
CostNode
One node of a cost-expression AST.
FkcError
A typed FKC import failure (Result-returning, never a panic).
RankSpec
Resolved
The result of lowering one kernel section: a primitive xor a fused record (exactly one of op_kind / fused_op).
ShapeAtom
Tri
A parsed layout tri-state (FKC §4.1). contiguous admits Required; the other four flags use only Accepted / Rejected. NotApplicable (n/a) is the “no constraint declared” value. An absent flag (YAML key omitted) defaults to Tri::Rejected for the capability flags (the conservative default matching today’s all-false KernelCaps).

Constants§

FKC_SUPPORTED_VERSIONS
The exact set of fkc_version values this importer accepts (FKC §10.1 / §11; KISS #450, narrowing §6.1-0008).

Statics§

CPU_AFFINE_CLAMP_POWI_ENTRY_POINTS
The CPU out-of-place scalar-param family’s symbol → production wrapper map (affine / clamp / powi × 4 dtypes + powi_backward × 4 = 16 kernels). Contract: fuel-dispatch/kernel-contracts/cpu/affine-clamp-powi.fkc.md. The scalar params (affine mul/add, clamp min/max, powi exp) ride in OpParams, NOT the dtype-list, so the binding keys stay [t, t] for the single-input forward ops and [t, t, t] for the two-input powi_backward. The ep! symbol is built from $op/$dt, so the three f32 hand-written wrappers whose fn-name differs from the symbol (clamp_elementwise_f32, powi_elementwise_f32) still map to the contract’s clamp_f32 / powi_f32 entry points.
CPU_ATTENTION_ENTRY_POINTS
The CPU attention family’s symbol → production wrapper map — the MIGRATED (KernelBindingTable) subset: forward FlashAttn (4 dtypes) + FlashAttnBackward{Q,K,V} (3 selectors × 4 dtypes) = 16 entry points. Contract: fuel-dispatch/kernel-contracts/cpu/attention.fkc.md.
CPU_BINARY_ENTRY_POINTS
The CPU elementwise-binary family’s symbol → production wrapper map (8 ops × 4 dtypes). The chassis umbrella section is registrable: false (§3.10 describe-only), so it never reaches resolution and is absent here.
CPU_COMPARE_ENTRY_POINTS
The CPU elementwise-COMPARE family’s symbol → production wrapper map (6 ops × 4 dtypes = 24). Contract: fuel-dispatch/kernel-contracts/cpu/compare-where.fkc.md. Each thunk is a single-(op,dtype) section (its lhs/rhs enumerate ONE dtype), so it does NOT fan — the importer resolves its declared symbol AS-IS. That symbol carries the _u8 output-mask suffix (T × T → U8 mask, return.out: fixed(U8)), so the ep! dtype slot is <dt>_u8 (e.g. eq_f32_u8), NOT the plain <dt> the binary/unary families use. The ## compare chassis umbrella is registrable: false (§3.10 describe-only) and never resolves, so it is absent here.
CPU_CONV_ENTRY_POINTS
The CPU 2D-convolution family’s symbol → production wrapper map — the FULL family: Conv2D + ConvTranspose2D × 4 dtypes = 8 symbols (each symbol serves BOTH operand-count keys). Contract: fuel-dispatch/kernel-contracts/cpu/conv.fkc.md. Each per-(op, dtype) section (## conv2d_f32, ## conv_transpose2d_f32, …) declares a SPECIFIC single-dtype entry_point (…::conv2d_f32), so none of them dtype-fan — the importer resolves that symbol AS-IS. Because the contract marks bias as optional: true, the importer’s key-builder fans each section into BOTH the no-bias key [T, T, T] (x, weight + out) and the with-bias key [T, T, T, T] (x, weight, bias + passthrough(x) output) — both resolving this SAME symbol/wrapper (the CPU wrapper handles 2 or 3 inputs). The spatial geometry (x_shape/w_shape/out_shape, stride/padding/[output_padding]/dilation, groups) rides in OpParams::{Conv2D, ConvTranspose2D}, NOT the dtype-list. This map is the SOLE registration path for the whole family: every hand-written table.register(Conv2D/ConvTranspose2D, …) reg (both operand counts) is DELETED.
CPU_FUSED_CONV_ROPE_ENTRY_POINTS
The CPU conv / RoPE / SSM FUSED family’s symbol → production wrapper map — the FULL audited: true conv-rope bundle. Contract: fuel-dispatch/kernel-contracts/fused/conv-rope.fkc.md.
CPU_FUSED_LINEAR_QUANT_ENTRY_POINTS
The CPU linear / quantized-matmul FUSED family’s symbol → production wrapper map — the MIGRATED subset of the audited: true linear-quant bundle. Contract: fuel-dispatch/kernel-contracts/fused/linear-quant.fkc.md.
CPU_FUSED_NORM_ENTRY_POINTS
The CPU norm/softmax FUSED family’s symbol → production wrapper map — the FIRST fused-registry link table (the fused_op analogue of the primitive CPU_*_ENTRY_POINTS). Contract: fuel-dispatch/kernel-contracts/fused/norm-softmax.fkc.md.
CPU_INPLACE_ENTRY_POINTS
The CPU in-place scalar-param family’s symbol → production wrapper map — the FULL family: 21 in-place unary ops (<op>_inplace, each fanned ×4 dtypes = 84) + InplaceAffine / ClampInplace / PowIInplace (affine_inplace / clamp_inplace / powi_inplace, 4 dtypes each = 12) = 96 entry points. Contract: fuel-dispatch/kernel-contracts/cpu/inplace-unary-affine.fkc.md.
CPU_MATMUL_ENTRY_POINTS
The CPU matmul family’s symbol → production wrapper map — the FULL portable family: bare batched MatMul (6 dtypes) + fused FusedLinear (matmul + bias-add, 4 dtypes) = 10 entry points. Contract: fuel-dispatch/kernel-contracts/cpu/matmul.fkc.md.
CPU_NORM_BACKWARD_ENTRY_POINTS
The CPU last-dim NORM-BACKWARD family’s symbol → production wrapper map (Softmax / LogSoftmax / RmsNorm / LayerNorm last-dim BACKWARD × 4 dtypes = 16). Contract: fuel-dispatch/kernel-contracts/cpu/norm-backward.fkc.md. Each per-(op, dtype) section (## softmax_last_dim_backward_f32, ## rms_norm_last_dim_backward_f32, …) declares a SPECIFIC single-dtype entry_point (…::softmax_last_dim_backward_f32), so none of them fan — the importer resolves that symbol AS-IS. The binding key is [T, T, T] — the BARE backward takes TWO inputs (softmax/log-softmax: the forward output y + the upstream gradient g; layer/rms-norm: the forward input x + g, stats recomputed) and writes ONE passthrough(y|x) output, and outer_count / last_dim / eps ride in OpParams::{SoftmaxLastDim,LogSoftmaxLastDim,NormLastDim}, NOT the dtype-list — identical to the deleted &binary(t) regs. The log_softmax backward wrapper fn-names (log_softmax_backward_<dt>_cpu_wrapper) differ from their log_softmax_last_dim_backward_<dt> symbol — the ep! symbol is built from the $op/$dt literals, so the mapping still binds the correct contract symbol (mirrors the forward log_softmax fn-vs-symbol case). This contract has NO ## chassis umbrella section, so there is no registrable: false describe-only entry to omit; the FORWARD forms live in the separate norm contract.
CPU_NORM_ENTRY_POINTS
The CPU last-dim NORM (forward) family’s symbol → production wrapper map (Softmax / LogSoftmax / RmsNorm / LayerNorm last-dim × 4 dtypes = 16). Contract: fuel-dispatch/kernel-contracts/cpu/norm.fkc.md. Each per-(op, dtype) section (## softmax_last_dim_f32, ## rms_norm_last_dim_f32, …) declares a SPECIFIC single-dtype entry_point (…::softmax_last_dim_f32), so none of them fan — the importer resolves that symbol AS-IS. The binding key is [T, T] (a SINGLE input + passthrough(input) output; the RMS/LayerNorm kernels carry NO affine gamma/beta operand — they are the bare normalization — and outer_count / last_dim / eps ride in OpParams::{SoftmaxLastDim,LogSoftmaxLastDim, NormLastDim}, NOT the dtype-list), identical to the deleted &unary(t) regs. The log_softmax wrapper fn-names (log_softmax_<dt>_cpu_wrapper) differ from their log_softmax_last_dim_<dt> symbol — the ep! symbol is built from the $op/$dt literals, so the mapping still binds the correct contract symbol (mirrors the clamp/powi/where fn-vs-symbol cases). This contract has NO ## chassis umbrella section, so there is no registrable: false describe-only entry to omit; the BACKWARD forms live in a separate norm-backward contract.
CPU_PADDING_ENTRY_POINTS
The CPU padding family’s symbol → production wrapper map — the FULL family: mode-unified forward Pad × 6 dtypes = 6 + PadBackward × 4 dtypes = 4 (all key [T, T]). Contract: fuel-dispatch/kernel-contracts/cpu/padding.fkc.md.
CPU_REDUCE_ENTRY_POINTS
The CPU per-axis REDUCE family’s symbol → production wrapper map (4 ops × 4 dtypes = 16). Contract: fuel-dispatch/kernel-contracts/cpu/reduce.fkc.md. Each per-(op, dtype) section (## sum_reduce_f32, …) declares a SPECIFIC single-dtype entry_point (…::sum_reduce_f32), so it does NOT fan — the importer resolves that symbol AS-IS. The binding key is [T, T] (input + passthrough(input) output; the reduce axes + keepdim ride in OpParams::Reduce, NOT the dtype-list). The ## reduce chassis umbrella is registrable: false (§3.10 describe-only) and never resolves, so it is absent here; the f32-only argmax_dim_f32 / argmin_dim_f32 sections are registrable: false (deferred — production registers Arg{Max,Min}Dim for all input dtypes via a hand-written dispatch) and are likewise absent.
CPU_REDUCE_TO_ENTRY_POINTS
The CPU broadcast-target REDUCE-TO family’s symbol → production wrapper map (ReduceSumTo / ReduceMaxTo × 4 dtypes = 8, key [T, T], + ReduceMaxToBackward × 4 dtypes = 4, key [T, T, T] = 12). Contract: fuel-dispatch/kernel-contracts/cpu/reduce-to.fkc.md. Each per-(op, dtype) section (## reduce_sum_to_f32, …) declares a SPECIFIC single-dtype entry_point (…::reduce_sum_to_f32), so it does NOT fan — the importer resolves that symbol AS-IS. The forward keys are [T, T] (input + passthrough(input) output; the target input_shape/output_shape ride in OpParams::ReduceSumTo / OpParams::ReduceMaxTo, NOT the dtype-list); the backward key is [T, T, T] (x, upstream + passthrough(x) output). The ## reduce_to chassis umbrella is registrable: false (§3.10 describe-only) and never resolves, so it is absent here (without it the chassis would double-register ReduceSumTo/[F32] → DuplicateKernelRef at init).
CPU_ROPE_ENTRY_POINTS
The CPU RoPE (rotary position embedding) family’s symbol → production wrapper map (1 op × 4 dtypes = 4). Contract: fuel-dispatch/kernel-contracts/cpu/rope.fkc.md. Each per-dtype section (## rope_f32, …) declares a SPECIFIC single-dtype entry_point (…::rope_f32), so none of them fan — the importer resolves that symbol AS-IS. The binding key is [T, T, T, T] — RoPE takes THREE inputs (x + the precomputed cos/sin tables, all one dtype; the [seq, head_dim] tables broadcast over the outer_count axis by the kernel re-indexing them per outer, NOT a stride-0 view) and writes ONE passthrough(x) output; outer_count / seq / head_dim ride in OpParams::Rope, NOT the dtype-list — identical to the deleted rope_dts(t) regs. This contract has NO ## chassis umbrella section, so there is no registrable: false describe-only entry to omit. RoPE is ALSO registered in the FusedKernelRegistry (register_default_fused_kernels, FusedOps::ROPE) — that is a SEPARATE registry seam and stays untouched; this map only serves the KernelBindingTable primitive path.
CPU_SHAPE_OPS_ENTRY_POINTS
The CPU shape-ops family’s symbol → production wrapper map — the MIGRATED subset (Flip + Roll + Concat + MaskedFill + WriteSlice + WriteSliceRotating dtype-fanned + CumSum per-dtype). Contract: fuel-dispatch/kernel-contracts/cpu/shape-ops.fkc.md.
CPU_SSM_ENTRY_POINTS
The CPU SSM / Mamba family’s symbol → production wrapper map — the FULL family: FusedSoftmaxCrossEntropy + CausalConv1d + SelectiveScan + SsdChunkScan (4 ops × 4 dtypes = 16). Contract: fuel-dispatch/kernel-contracts/cpu/ssm.fkc.md. Each per-(op, dtype) section (## fused_softmax_cross_entropy_f32, ## selective_scan_f32, …) declares a SPECIFIC single-dtype entry_point (…::selective_scan_f32), so none of them fan — the importer resolves that symbol AS-IS. Binding keys:
CPU_UNARY_ENTRY_POINTS
The CPU elementwise-unary family’s symbol → production wrapper map (22 ops × 4 dtypes = 88 kernels). Contract: fuel-dispatch/kernel-contracts/cpu/elementwise-unary.fkc.md. Each per-op section declares a BASE entry_point (e.g. …::relu) and enumerates dtypes: [F32,F64,BF16,F16]; the importer’s §3.4 multi-dtype fan-out then resolves <base>_<dtype> (e.g. relu_f32) against this table — so the $op literals below are the byte-kernel BASES, NOT the OpKind names. The two GELU flavors stay distinct, and since S13 their OpKind names no longer match their (unrenamed) byte-kernel bases: OpKind::GeluTanhElementwise (the canonical tanh GELU) has base gelu (wrapper gelu_elementwise_<dt>), while OpKind::GeluElementwise (bare Gelu means erf since S13) has base gelu_erf (wrapper gelu_erf_elementwise_<dt>). The unary chassis umbrella is registrable: false (§3.10 describe-only) and never resolves, so it is absent here.
CPU_WHERE_ENTRY_POINTS
The CPU ternary-select (where) family’s symbol → production wrapper map (1 op × 4 dtypes = 4). Contract: fuel-dispatch/kernel-contracts/cpu/compare-where.fkc.md. The single where_kernel section enumerates a/b dtypes: [F32,F64,BF16,F16], so it FANS (§3.4): its declared BASE entry_point …::where resolves <base>_<dtype> = where_{f32,f64,bf16,f16} against this table. The binding key is [U8, T, T, T] (cond U8 + a/b/out share T; out: passthrough(a) → T).

Traits§

LinkRegistry
Resolve a contract’s entry_point symbol string into a concrete KernelRef function pointer. Each provider crate implements this over its exported &'static [(&str, KernelRef)] table (FKC §12.6); a test stub maps every symbol to a dummy kernel.

Functions§

bind_cost_symbols
Bind the §2.3 cost-expression symbol vocabulary (m/n/k/batch/ dtype_bytes, plus a generic element count) from a dispatch context, so a contract’s declared cost expression can be evaluated to a concrete FLOP count. Op-specific symbols come from OpParams; the vocabulary extends as declared-cost contracts for more op families land.
compute_revision
Compute (or parse) a kernel’s KernelRevisionHash (§4.7).
cost_estimate
The cost trampoline: evaluate a contract’s declared cost expression against a dispatch context, turning a parsed CompiledCostExpr into a concrete CostEstimate — the value FKC import previously dropped in favor of the unknown_cost sentinel. An undefined symbol is a typed CostEvalError (never a panic, never a silent zero). bytes_moved stays 0 until contracts carry a separate bytes: expression.
eval_cost
Evaluate a CompiledCostExpr against bindings (symbol → capacity value). The CompiledCostExpr::Unknown sentinel evaluates to 0.0.
fused_unknown_cost
The fused-op cost-fn sentinel — the fused analog of unknown_cost. There is no public fused sentinel in fused.rs (registrations that omit a cost use CostEstimate::default() inline), so the importer supplies its own trivial zero-cost fn matching the fused cost-fn signature fn(&[Shape], &FusedOpParams, &BackendCapabilities) -> CostEstimate.
import_bundle
Convenience: read a bundle file at path, then import_bundle_str.
import_bundle_str
Parse + validate a single bundle markdown file’s bytes into an ImportedProvider. Pure: no I/O of its own (tests pass &str).
import_glob
Glob multiple per-kernel / per-bundle FKC files into one provider (§9.2). Each matched file is parsed + lowered independently and then merged into a single ImportedProvider; the front-matter provider.name / provider.backend / provider.kernel_source must agree across every file or FkcError::ProviderMismatch.
is_generic_contract
Is this contract the GENERIC (fully-permissive strided) one — admissible anywhere because it imposes no structure tightness?
lower_file
Lower every kernel section of a parsed file into Resolved records, using the file’s front-matter for the backend / kernel_source / revision_base defaults and resolving entry points through link.
parse_file
Parse an FKC file’s text into an FkcFile (front-matter + kernels).
parse_path
Read a file at path, then parse_file.
parse_rank_spec
4 | any | 2..=4 | 2.. -> RankSpec; None on anything else.
parse_shape_constraint
solve_probe_shapes
Seed the probe combos for §3.5 shape-solver rank resolution, then APPLY the structural atoms (Task 1.3): same_as/broadcast_to copy a source operand’s (already-solved) dims, dim[i]=<expr> evaluates an expression (reusing cost_expr::CostNode, including a bare shared symbol like matmul’s k), and divisible(dim[i], v) rounds an axis UP to a multiple of v. Atoms are applied in DEPENDENCY order (Task 1.4): an operand whose same_as=k/dim[i] references another operand k is applied AFTER k, even if k is declared later in inputs — a bounded Kahn topo sort over the Task-1.3 SOLVE-KEYS, computed once (constraints don’t vary by profile). A dependency cycle (a: same_as=b, b: same_as=a) never hard-errors: it degrades to ONE cycle ImportWarning and the cyclic operands are applied best-effort in source order (each copies whatever seed/partial value the other currently holds). Parses each operand’s shape_constraint up front so a malformed-vocabulary segment hard-errors before any probe is built.
validate_file
Run the full V-FKC-* battery over a parsed file. The caller (the lint / import_bundle_str) runs this after parse so a structurally-bad contract fails import. Stops at the first violation (a typed FkcError).
validate_kernel
Validate one parsed kernel section against the structural + coherence rules (every rule that operates on the parsed form). The duplicate- KernelRef rule (10) is a register-time check (finalize), not here.

Type Aliases§

ProbeCombo