Ir.Schedule_outcometype phase = | Transform| Hardware_limits| Backend_codegen| Backend_compile| Backend_link| PreflightContext.check_launch_bindings: the per-candidate part of a launch's pre-dispatch validation — out-of-range static bindings. It precedes Ir.Task.run, so classify_raw never makes one fatal (gh-ocannl-564): nothing was dispatched, the failure is the caller's to fix and retry, and the lineage stays usable. Inside a Launch-tagged boundary it was instead unattributable, hence fatal, hence a condemned lineage for a one-line user mistake.
Deliberately NOT the lineage-wide part (Context.check_lineage_runnable: poisoned lineage, uninitialized inputs, unexecuted dependencies), which a search raises outside this region — it fails every candidate at once, so containing it would report a completed search that timed nothing (gh-ocannl-569).
| Launch| Syncval sexp_of_phase : phase -> Sexplib0.Sexp.tWhat a Resource_exceeded candidate asked too much of. One variant per launch dimension, although the grid pair shares the single Backend_intf.hardware_limits.max_grid_yz cap and the workgroup triple shares one Backend_intf.hardware_limits.max_workgroup_dims array: the dimensions are shrunk by different knobs — an over-.y grid by coarsening the row blocking, an over-.z grid by keeping batch loops serial, an over-.z workgroup by re-tiling the outermost annotated thread loop — and this is the rejection key an autotune search groups declines under (key_of_cause). The limit is shared where it is one hardware fact; the resource is distinct because it is a schedule-side dimension.
Workgroup_x_extent / Workgroup_y_extent / Workgroup_z_extent are per-dimension and therefore not implied by Workgroup_threads, which caps only the thread product: on CUDA a 2 x 2 x 128 workgroup is 512 threads (legal) with a .z of 128 against a cap of 64 (gh-ocannl-679).
Device_memory is the one resource that is not a launch dimension: the device refused a buffer allocation (Device_memory_exhausted, gh-ocannl-1326). Its requested is the bytes of the allocation the driver refused, its limit the driver's free bytes read right after the refusal (None where the backend cannot read them).
val sexp_of_resource : resource -> Sexplib0.Sexp.ttype severity = | Expected| Compiler_bug| ConfigurationThe toolchain configuration rejects any code, not this code (gh-ocannl-1350): an explicit compiler setting the compiler does not accept, a compiler command that names no compiler, a broken local toolchain. A user error, so exception_of_cause renders it as Utils.User_error.
| EnvironmentThe host refused an artifact the compiler built, for a reason that is neither the code nor the configuration (gh-ocannl-1717): a code-signing or system-policy refusal at load, a library that is missing after a successful compile. Typically transient -- a policy daemon or a filesystem under load -- so rerunning usually succeeds. exception_of_cause renders it as Failure: the operation failed, but the caller misused nothing (which Invalid_argument would claim) and has nothing to fix (which Utils.User_error would).
val sexp_of_severity : severity -> Sexplib0.Sexp.tval sexp_of_execution_effect : execution_effect -> Sexplib0.Sexp.tval compare_execution_effect : execution_effect -> execution_effect -> intval equal_execution_effect : execution_effect -> execution_effect -> booltype cause = | Illegal_schedule of {}| Unsupported of {}| Resource_exceeded of {resource : resource;requested : int;limit : int option;detail : string;}| Backend_rejected of {backend : string;stage : string;severity : severity;detail : string;}| Unclassified of {phase : phase;exn_constructor : string;detail : string;}| Seed_evicted of {}A detected seed site the search declined to propose because a candidate-volume cap bound (gh-ocannl-541): the site was reachable and ranked, and lost only to the cap. Recorded in the decline census so a previously-proposed site that stops being proposed leaves a signal instead of vanishing. family names the seed family (e.g. "split_reduce").
| Not_dispatched of {}A candidate the search refused to run on a GPU backend because it binds no hardware dimension (gh-ocannl-532): the whole routine would execute in one work-item. Nothing is wrong with the candidate — the backend's execution model is what rejects it — but it is a decline like any other, and leaving it out of the census made a GPU search that timed one candidate indistinguishable from one whose candidates all failed (gh-ocannl-543). origin names where the refusal happened: "baseline" (the serial baseline), "candidate" (a compiled candidate that degenerated to a serial form), or "beam_move" (a menu move pruned before compile because it provably cannot parallelize an already unparallelized incumbent).
val sexp_of_cause : cause -> Sexplib0.Sexp.tval sexp_of_rejection_key : rejection_key -> Sexplib0.Sexp.tval compare_rejection_key : rejection_key -> rejection_key -> intval equal_rejection_key : rejection_key -> rejection_key -> boolval key_of_cause : cause -> rejection_keyval detail_of_cause : cause -> stringval exception_of_cause : cause -> exnThe stage of a Backend_rejected raised when the host's dynamic loader refuses a kernel the compiler built. Compiler_bug for an undefined symbol or a missing dependency (gh-ocannl-1077); Environment for a code-signing or policy refusal, or a library gone by the time it is loaded (gh-ocannl-1717).
The compiler reported success but its library did not appear before the timeout: an Environment rejection (gh-ocannl-1717).
The requested host signing step rejected the compiled library: a Configuration rejection, since the step runs only when cc_backend_verify_codesign asks for it (gh-ocannl-1728).
The stage of a Configuration rejection at Backend_compile: the kernel failed to compile, and so did a trivial kernel under the same command and flags (gh-ocannl-1350).
Whether a typed cause must end a search rather than decline one candidate: protect makes it Fatal although it is typed. Exactly three post-compile host-boundary stages at Backend_link are uncontainable: artifact_missing_stage violates the successful compiler's output contract; codesign_stage rejects a host/toolchain prerequisite; dlopen_stage refuses a library the compiler built. The first two provide no evidence against a candidate's schedule (gh-ocannl-1142). The third can correlate with candidates: gh-ocannl-1045's missing -lm broke only kernels referencing libmvec, so absorbing it quietly favored slower candidates avoiding those symbols (gh-ocannl-1077). A JIT rejecting one candidate's PTX remains a counted decline. So is a compiler rejecting one candidate's source, except at toolchain_stage: a toolchain that compiles nothing would reject every candidate alike (gh-ocannl-1350).
type fatal = {exn : exn;backtrace : Stdlib.Printexc.raw_backtrace;phase : phase;candidate : string option;cause : cause option;The typed cause of a fatal failure that has one: an uncontainable cause, or one escalated by fatal_of_classified. None for an exception nothing classified.
}phase is where the failure was raised, not where the enclosing protect was installed: a narrow tag or a preserved cause reports its own phase, and a backend classifier's answer is pinned to the phase it was handed. This is what lets a report say whether a candidate died at link, at launch, or at sync.
val sexp_of_classified_cause : classified_cause -> Sexplib0.Sexp.tval equal_classified_cause : classified_cause -> classified_cause -> booltype 'a outcome = ('a, failure) Stdlib.Result.tval fatal_of_classified : ?candidate:string -> classified_cause -> fatalEscalates a classified rejection that cannot be contained after all — a launch failure whose execution effect is Writes_may_have_occurred, with no API to restore the damaged lineage. The cause is rendered into its public exception; the backtrace is the escalation site, since the original raise was already contained.
exception Raised_at of phase * exn * Stdlib.Printexc.raw_backtraceexception Device_memory_exhausted of {backend : string;requested : int;Bytes of the one allocation the device refused.
*)free : int option;The driver's free bytes, read after the refusal.
*)detail : string;The driver's own report.
*)}The device refused a buffer allocation (gh-ocannl-1326). Raised by a GPU backend's pool allocator in place of its driver's out-of-memory error, so that every allocation site — a compile's delta, a transfer's destination — reports it in one backend-independent shape. protect classifies it as a contained Resource_exceeded Device_memory decline with No_device_writes, whatever the backend's own classifier says (an allocation precedes any dispatch); Autotune.tune refuses a whole search when its baseline compile, one candidate's footprint, meets it.
val sexp_of_provenance : provenance -> Sexplib0.Sexp.tval compare_provenance : provenance -> provenance -> intval equal_provenance : provenance -> provenance -> boolval protect :
?strict:bool ->
classify_backend:(phase -> exn -> classified_cause option) ->
provenance:provenance ->
phase:phase ->
?candidate:string ->
(unit -> 'a) ->
'a outcomeRuns a phase boundary while preserving typed causes and raw backtraces. strict is exposed for policy tests; production callers should omit it and use strict_failure_classification.
val tag : phase -> (unit -> 'a) -> 'aTags an exception with the narrow phase where it was raised, preserving its raw backtrace. Existing typed transport exceptions pass through unchanged.
val raise_cause : cause -> _Renders a typed internal cause using the exception contract of the existing public APIs.
val raise_failure : failure -> _Re-raises a fatal failure with its original backtrace, or renders a classified cause.