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```fkcblock (§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§
- Accept
Block - The
accept:block. - Caps
Block - Capability block (§4.1–§4.6).
- Cost
Block - Cost block (§4.4). Coefficient EXPRESSION fields stay
String— FKC’s own parser reads them later, NOT YAML.~(YAML null) deserializes toNone. - Cost
Eval Error - An eval failure (an undefined symbol, or division by zero).
- Cost
Memory - Per-tier memory footprint (§4.4). Each tier is an expression
String(or a literal0); kept as a raw scalar so0and"n * 4"both parse. - CpuLink
Registry - The built-in CPU backend’s
LinkRegistry— resolves a contract’sentry_pointsymbols againstCPU_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, andCPU_CAST_ENTRY_POINTS. Unresolved →None, which the importer turns into a typedUnknownEntryPointerror (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. - FkcFront
Matter - The file-level
----fenced YAML front-matter (§3.1). - FkcKernel
- The per-kernel
```fkcstructured contract (§3.3). - FkcProvider
- Provider identity (front-matter
provider:mapping, §3.1). - Gather
Spec - Paged / indexed-residency (gather) operand spec (§3.9.1).
- Import
Warning - A single non-fatal FKC import diagnostic.
- Imported
Provider - 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_intoonly does the registry inserts + the duplicate-detection gate. - Layout
Spec - The five-flag layout capability set (§4.1). Each flag is a string tri-state
(
required/accepted/n/aforcontiguous;accepted/rejectedfor the rest) carried verbatim — projection onto today’sKernelCaps.strided_inputis a lowering concern (§6). - OpParam
Field Spec - A single op-param field spec (
{ kind, constraint?, note? }, §3.7). - OpParams
Schema - Op-param schema (§3.7): names the params variant + per-field constraints.
- Output
Desc - An output descriptor + return rules (§5.1–§5.4). Rule fields are
Stringexpressions parsed by FKC later, not YAML. - Precision
Block - Precision block (§4.8) →
PrecisionGuarantee. Bound fields are raw scalars (0, a float, or~); the typed conversion is a lowering concern. - Quant
Spec - Quant facts (§3.2
fdx.quant:). All tokens areString(disarms Norway; the typed conversion is a lowering concern). - Resolved
Fused - A fully-lowered fused (
fused_op) contract — analogous toResolvedPrimitivebut targeting theFusedKernelRegistry(FusedOpIdinstead ofOpKind; the fused cost target). - Resolved
Layout - The full typed five-flag layout set for one operand — every flag
retained, even the ones not yet projected onto
KernelCaps(§6 [consumer-ahead]). - Resolved
Primitive - 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 aCostFnfn-pointer (the trampoline is the next slice). - Return
Block - The
return:block. - Shape
Constraint - Tensor
Desc - A tensor descriptor (operand or, with return rules, an output; §3.2).
Enums§
- Axis
Index - Compiled
Cost Expr - A compiled cost-expression AST (FKC §4.4 / §2.3 strategy A).
- Cost
Node - One node of a cost-expression AST.
- FkcError
- A typed FKC import failure (
Result-returning, never a panic). - Rank
Spec - Resolved
- The result of lowering one kernel section: a primitive xor a fused
record (exactly one of
op_kind/fused_op). - Shape
Atom - Tri
- A parsed layout tri-state (FKC §4.1).
contiguousadmitsRequired; the other four flags use onlyAccepted/Rejected.NotApplicable(n/a) is the “no constraint declared” value. An absent flag (YAML key omitted) defaults toTri::Rejectedfor the capability flags (the conservative default matching today’s all-falseKernelCaps).
Constants§
- FKC_
SUPPORTED_ VERSIONS - The exact set of
fkc_versionvalues 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 wrappermap (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 inOpParams, NOT the dtype-list, so the binding keys stay[t, t]for the single-input forward ops and[t, t, t]for the two-inputpowi_backward. Theep!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’sclamp_f32/powi_f32entry points. - CPU_
ATTENTION_ ENTRY_ POINTS - The CPU attention family’s
symbol → production wrappermap — the MIGRATED (KernelBindingTable) subset: forwardFlashAttn(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 wrappermap (8 ops × 4 dtypes). The chassis umbrella section isregistrable: 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 wrappermap (6 ops × 4 dtypes = 24). Contract:fuel-dispatch/kernel-contracts/cpu/compare-where.fkc.md. Each thunk is a single-(op,dtype) section (itslhs/rhsenumerate ONE dtype), so it does NOT fan — the importer resolves its declared symbol AS-IS. That symbol carries the_u8output-mask suffix (T × T → U8mask,return.out: fixed(U8)), so theep!dtype slot is<dt>_u8(e.g.eq_f32_u8), NOT the plain<dt>the binary/unary families use. The## comparechassis umbrella isregistrable: 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 wrappermap — 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-dtypeentry_point(…::conv2d_f32), so none of them dtype-fan — the importer resolves that symbol AS-IS. Because the contract marksbiasasoptional: 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 inOpParams::{Conv2D, ConvTranspose2D}, NOT the dtype-list. This map is the SOLE registration path for the whole family: every hand-writtentable.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 wrappermap — the FULLaudited: trueconv-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 wrappermap — the MIGRATED subset of theaudited: truelinear-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 wrappermap — the FIRST fused-registry link table (thefused_opanalogue of the primitiveCPU_*_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 wrappermap — 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 wrappermap — the FULL portable family: bare batchedMatMul(6 dtypes) + fusedFusedLinear(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 wrappermap (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-dtypeentry_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 outputy+ the upstream gradientg; layer/rms-norm: the forward inputx+g, stats recomputed) and writes ONEpassthrough(y|x)output, and outer_count / last_dim / eps ride inOpParams::{SoftmaxLastDim,LogSoftmaxLastDim,NormLastDim}, NOT the dtype-list — identical to the deleted&binary(t)regs. Thelog_softmaxbackward wrapper fn-names (log_softmax_backward_<dt>_cpu_wrapper) differ from theirlog_softmax_last_dim_backward_<dt>symbol — theep!symbol is built from the$op/$dtliterals, so the mapping still binds the correct contract symbol (mirrors the forwardlog_softmaxfn-vs-symbol case). This contract has NO##chassis umbrella section, so there is noregistrable: falsedescribe-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 wrappermap (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-dtypeentry_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 — andouter_count/last_dim/epsride inOpParams::{SoftmaxLastDim,LogSoftmaxLastDim, NormLastDim}, NOT the dtype-list), identical to the deleted&unary(t)regs. Thelog_softmaxwrapper fn-names (log_softmax_<dt>_cpu_wrapper) differ from theirlog_softmax_last_dim_<dt>symbol — theep!symbol is built from the$op/$dtliterals, 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 noregistrable: falsedescribe-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 wrappermap — the FULL family: mode-unified forwardPad× 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 wrappermap (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-dtypeentry_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 inOpParams::Reduce, NOT the dtype-list). The## reducechassis umbrella isregistrable: false(§3.10 describe-only) and never resolves, so it is absent here; the f32-onlyargmax_dim_f32/argmin_dim_f32sections areregistrable: 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 wrappermap (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-dtypeentry_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 targetinput_shape/output_shaperide inOpParams::ReduceSumTo/OpParams::ReduceMaxTo, NOT the dtype-list); the backward key is[T, T, T](x, upstream +passthrough(x)output). The## reduce_tochassis umbrella isregistrable: false(§3.10 describe-only) and never resolves, so it is absent here (without it the chassis would double-registerReduceSumTo/[F32]→DuplicateKernelRefat init). - CPU_
ROPE_ ENTRY_ POINTS - The CPU RoPE (rotary position embedding) family’s
symbol → production wrappermap (1 op × 4 dtypes = 4). Contract:fuel-dispatch/kernel-contracts/cpu/rope.fkc.md. Each per-dtype section (## rope_f32, …) declares a SPECIFIC single-dtypeentry_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 precomputedcos/sintables, all one dtype; the[seq, head_dim]tables broadcast over theouter_countaxis by the kernel re-indexing them per outer, NOT a stride-0 view) and writes ONEpassthrough(x)output; outer_count / seq / head_dim ride inOpParams::Rope, NOT the dtype-list — identical to the deletedrope_dts(t)regs. This contract has NO##chassis umbrella section, so there is noregistrable: falsedescribe-only entry to omit. RoPE is ALSO registered in theFusedKernelRegistry(register_default_fused_kernels,FusedOps::ROPE) — that is a SEPARATE registry seam and stays untouched; this map only serves theKernelBindingTableprimitive path. - CPU_
SHAPE_ OPS_ ENTRY_ POINTS - The CPU shape-ops family’s
symbol → production wrappermap — 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 wrappermap — 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-dtypeentry_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 wrappermap (22 ops × 4 dtypes = 88 kernels). Contract:fuel-dispatch/kernel-contracts/cpu/elementwise-unary.fkc.md. Each per-op section declares a BASEentry_point(e.g.…::relu) and enumeratesdtypes: [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$opliterals 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 basegelu(wrappergelu_elementwise_<dt>), whileOpKind::GeluElementwise(bareGelumeans erf since S13) has basegelu_erf(wrappergelu_erf_elementwise_<dt>). Theunarychassis umbrella isregistrable: false(§3.10 describe-only) and never resolves, so it is absent here. - CPU_
WHERE_ ENTRY_ POINTS - The CPU ternary-select (
where) family’ssymbol → production wrappermap (1 op × 4 dtypes = 4). Contract:fuel-dispatch/kernel-contracts/cpu/compare-where.fkc.md. The singlewhere_kernelsection enumeratesa/bdtypes: [F32,F64,BF16,F16], so it FANS (§3.4): its declared BASEentry_point…::whereresolves<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§
- Link
Registry - Resolve a contract’s
entry_pointsymbol string into a concreteKernelReffunction 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 fromOpParams; 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
CompiledCostExprinto a concreteCostEstimate— the value FKC import previously dropped in favor of theunknown_costsentinel. An undefined symbol is a typedCostEvalError(never a panic, never a silent zero).bytes_movedstays 0 until contracts carry a separatebytes:expression. - eval_
cost - Evaluate a
CompiledCostExpragainstbindings(symbol → capacity value). TheCompiledCostExpr::Unknownsentinel evaluates to0.0. - fused_
unknown_ cost - The fused-op cost-fn sentinel — the fused analog of
unknown_cost. There is no public fused sentinel infused.rs(registrations that omit a cost useCostEstimate::default()inline), so the importer supplies its own trivial zero-cost fn matching the fused cost-fn signaturefn(&[Shape], &FusedOpParams, &BackendCapabilities) -> CostEstimate. - import_
bundle - Convenience: read a bundle file at
path, thenimport_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-matterprovider.name/provider.backend/provider.kernel_sourcemust agree across every file orFkcError::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
Resolvedrecords, using the file’s front-matter for the backend / kernel_source / revision_base defaults and resolving entry points throughlink. - parse_
file - Parse an FKC file’s text into an
FkcFile(front-matter + kernels). - parse_
path - Read a file at
path, thenparse_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_tocopy a source operand’s (already-solved) dims,dim[i]=<expr>evaluates an expression (reusingcost_expr::CostNode, including a bare shared symbol like matmul’sk), anddivisible(dim[i], v)rounds an axis UP to a multiple ofv. Atoms are applied in DEPENDENCY order (Task 1.4): an operand whosesame_as=k/dim[i]references another operandkis applied AFTERk, even ifkis declared later ininputs— 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 ONEcycleImportWarningand the cyclic operands are applied best-effort in source order (each copies whatever seed/partial value the other currently holds). Parses each operand’sshape_constraintup 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 typedFkcError). - validate_
kernel - Validate one parsed kernel section against the structural + coherence
rules (every rule that operates on the parsed form). The duplicate-
KernelRefrule (10) is a register-time check (finalize), not here.