The silent-failure index¶
Every ⚠️ callout in the series — 1831 of them, 1469 describing a concrete silent failure — in one place, sorted by the symptom you would observe.
The defining property of this stack is that most defects do not throw. Each entry below links to the guide section that documents the failure, its trigger, and the safe default. Entries are classified by what you see (or fail to see), not by which API is at fault, because the symptom is what you start from at 2 a.m.
Generated from the guides on 2026-10-09 by
scripts/tooling; regenerate after editing guides rather than editing this file by hand.
How to use this page¶
Start from the symptom column that matches what you observe. Within each section, entries run in part order — Foundation Models first (parts 1–6), Core AI (7–10), Metal (11), MLX (12–13), then bridges, shipping, adjacent capabilities and migration (14–17).
The symptoms¶
| Symptom | Entries | What it means |
|---|---|---|
| Wrong output | 179 | Runs and returns output that is wrong — wrong numbers, garbled or wrong-language text, corrupted tensors. |
| Empty output / no-op | 67 | Runs and returns nothing where content is expected — nil, empty results, operations that quietly do nothing. |
| Truncation & limits | 27 | Input or output silently truncated or capped — context windows, response sizes, token budgets. |
| Ignored input | 114 | A parameter, flag, option, file or annotation is silently ignored, dropped, or overridden. |
| Stale state | 41 | Stale or cached data served; invalidation that did not happen (or happened unexpectedly). |
| Data & artifact loss | 39 | Silent loss or overwrite of data or build artifacts — purged assets, dead bookmarks, unrebuildable builds. |
| Compiles but unavailable | 90 | Builds fine, then fails or degrades at runtime for some users — OS floors, device eligibility, missing assets, entitlements. |
| Performance cliffs | 156 | Silent slowdowns — CPU/GPU fallback, ANE ineligibility, cache misses, respecialization, sync stalls. |
| Resource growth | 40 | Silent memory or disk growth, leaks, quota consumption. |
| Precision loss | 18 | Silent numeric precision or dtype changes — TF32, quantization side-effects, accumulation regimes. |
| Misleading signals | 167 | Errors, logs or metrics that name the wrong cause; swallowed errors; observation APIs that emit nothing. |
| Version drift | 102 | The same code or artifact behaves differently across OS/SDK/tool versions with no signal. |
| Docs vs reality | 159 | Documented behavior differs from what ships — samples that don't compile, wrong signatures, naming mismatches. |
| API footguns | 270 | API shapes that invite silent misuse — surprising defaults, order-dependence, overload traps. |
| General cautions | 362 | Warnings and considerations that are not themselves silent failures. |
Wrong output¶
Runs and returns output that is wrong — wrong numbers, garbled or wrong-language text, corrupted tensors.
Part 2
- Prompt injection never throws — a successful attack reads as a normal Response; token caps also truncate with no flag. — 2.README 🔇
- SpotlightSearchTool hands the model identity attributes only — bodies never arrive and it invents them fluently. — 2.README 🔇
- EXIF-rotated camera photos load sideways and get fluent wrong answers; summarizeHistory also flattens attachments away. — 2.README 🔇
- A successful prompt injection returns a clean Response with plausible text — no error, guardrail case, or trace shows… — 2.1 🔇
- includeSchemaInPrompt:false without a full example still yields well-formed objects — field semantics quietly degrade. — 2.1 🔇
- Schema off, no example: still structurally valid output, just worse — wrong emphasis, empty strings, grammar padding. — 2.2 🔇
- Contents entry: the metadata gap — the Spotlight defect where the model invents document bodies. — 2.4
- Heading: the metadata gap — the defect that will burn you. — 2.4
- The tool call succeeds and returns well-formed items with no bodies — the model's answer is fluent, specific, invented. — 2.4 🔇
- A URL judged by UTType only — renamed .txt, zero-byte, unscoped file — attaches fine; the answer describes nothing. — 2.5 🔇
- EXIF orientation 6 without correction sends the image sideways — the model calls a standing person lying down. — 2.5 🔇
Part 3
- Small or thinking models can emit invalid tool JSON; third-party results need model-specific validation — 3.1
- Heading: the consultation that quietly returns nonsense. — 3.4
- A failed child-session consultation reaches the parent as ordinary tool output — and the parent model believes it. — 3.4 🔇
Part 4
- Over-declaring supportsGuidedGeneration for a local server can return well-formed JSON with invented fields. — 4.README 🔇
- Declaring guided generation a server ignores yields parse failures or well-formed output with invented fields. — 4.2 🔇
- Backend table: ChatCompletions delegates schema enforcement to the server — strictness is whatever the server does. — 4.2
- Comparison table: @Generable is server-delegated on ChatCompletions and lost on Core AI's pipelined engine. — 4.2
- Over-declaring .guidedGeneration never throws — it returns malformed JSON at the parse boundary or invented fields. — 4.3 🔇
- The id latch concatenates repeated tool-call ids into call_1call_1…, and the else-if drops content sharing a chunk. — 4.3
Part 5
- A tool named in instructions but missing from the toolset loops the model: fluent wrong-mode output and no error. — 5.1
- The canonical bug: instructions name a tool the toolset lacks; the model loops in brainstorm mode, output stays… — 5.1
- Every layer behaves correctly while the user sees the wrong feature — the model can't switch modes and nothing throws. — 5.1
- The model kept accepting input and making tool calls, never threw, and gave no signal — Apple's archetypal silent… — 5.1 🔇
- token_count([]) takes the tools path (vacuous all()) and returns the empty toolset's count, not a prompt count. — 5.2
- Image input is unreliable for spatial localisation — confident answers that misplace regions (thread 838613). — 5.2
Part 6
- Expert and judge scores pair by index; any reorder, filter or dropped call shifts pairs — kappa reads a plausible 0-0.2. — 6.2
- ?? 0.0 turns a missing expert score into an off-scale fifth category, skewing p_chance and depressing kappa beyond one… — 6.2
- The generating session has no tools registered; it invents lookalike names and the samples look valid but score as… — 6.3
Part 7
- Observed zero storage is not an initialization contract; explicitly write every NDArray element that matters. — 7.1
- Indexing by hand while ignoring interleaveLayout reads the wrong elements — the strides are block strides for that axis — 7.1
- Assuming the output dtype from the input descriptor misreads bytes — outputs can be a different scalar type — 7.1
- Output scalarType can differ from the input's — inspecting the array itself is the only safe way to decode it — 7.1
- EXIF orientation is handled by no layer — the same JPEG tensorizes differently depending on the loader — 7.1
- apple/coreai-models has zero EXIF handling and its two image entry points disagree — rotated photos give wrong tensors — 7.1 🔇
- NDArray.from_descriptor only sizes the buffer — on Linux unzeroed state reads garbage; allocate np.zeros explicitly — 7.3
- memset-zeroing the whole addressable range clobbers aliased buffers — exactly the AsyncValue(unsafeBuffer:) situation — 7.3
- x.mul_(2) on a forward arg silently reclassifies the input as state — positional Swift bindings shift one slot — 7.3
- Uninitialised state storage: nothing documents that Swift NDArray inits zero — unzeroed KV reads garbage on first use — 7.3
- Two concurrent run() calls sharing one KV cache race — exclusivity checks don't span async tasks; one loop per state set — 7.3
- Omit image_mean/image_std and you silently get CLIP's — Qwen3-VL-class models produce degraded captions, not an error — 7.4
- Validate input names and state metadata; positional legacy consumers can silently misbind reordered arrays. — 7.4
- Fixed bug: pipelined sampling shared one execution descriptor across steps, corrupting text at temperature > 0 — 7.4 🔇
- Substring tensor-role discovery picks the first ambiguous match and can wire the wrong intermediate without a… — 7.5 🔇
Part 8
- Mutating an input changes the state ABI; same-shape buffers can reorder across a PyTorch upgrade — 8.README 🔇
- SDPA lower-right and PyTorch upper-left causal masks agree on square inputs but differ on decode steps. — 8.README 🔇
- MTLTensor extents reverse the torch shape — a kernel correct in torch coordinates reads the wrong axes in Metal — 8.README 🔇
- State ordering is an assumption — same-shape buffers like k_cache/v_cache can swap slots and every check still passes — 8.1
- k_cache and v_cache can swap positions across a PyTorch upgrade — Swift binds key to the value slot and output is… — 8.1 🔇
- NDArray.from_descriptor only sizes the buffer — on Linux, buffer-state reads return garbage on the first call — 8.1
- Seventeen open defects across the repos produce plausible, correct-shaped output with no diagnostic — four still unfixed — 8.2 🔇
- SDPA has two conversion routes with one name — their attribute schemas and mask conventions differ — 8.2
- The causal-mask convention differs between the two SDPA routes when query and key lengths differ — masks land wrong — 8.2 🔇
- RoPE requires fp32, and partial-rotary mode pairs the wrong dimensions — a known acknowledged issue — 8.2
- Community partial-rotary RoPE measurements found wrong dimension pairing; validate the reference convention — 8.2 🔇
- fp16 casting ignores activation overflow in softplus/mish/logsumexp — the sanctioned fix is rewriting your module — 8.2
- Compression shifts activation distributions — values once below the fp16 overflow threshold can newly exceed it — 8.2
- Integer true divide ran as int division then cast — fractions dropped on every backend (PR #32; latent twin in div) — 8.2 🔇
- 0.4.3 packed cat silently concatenates on dim 0; apple/coreai-torch#41 merged outside that tag — 8.2 🔇
- sum/prod on int64 reduced in int32 — silently wrapping identically on every backend, corrupting the lowered IR — 8.2 🔇
- The axis reversal: MTLTensor extents are the reverse of the torch shape, and subscripts reverse too — 8.3
- Torch (D0,D1,D2) arrives in the kernel as (D2,D1,D0) — your correct torch_defn cannot catch the reversed Metal body — 8.3 🔇
- torch_defn is shape inference only — a kernel emitting zeros or NaN converts cleanly; write the numeric test yourself — 8.3 🔇
- A literal result_shapes under a dynamic input compiles fine — at other runtime sizes the kernel writes the stale shape — 8.3
- result_shapes=[2,2,3] freezes into a ?x2x3 graph — when dim 0 arrives as 7, nothing objects; use list(x.shape) always — 8.3 🔇
- Naked exp() in a hand-written softmax overflows — subtract the running max first, as Apple's own fixture does — 8.3
Part 9
- Now-fixed axis bug in coreai::quantize/dequantize — worth knowing when reading older artifacts — 9.1
- Historical negative-axis bug fixed before 0.4.3 by apple/coreai-torch#24 — 9.1 🔇
- Pool/flatten share one FakeQuantize between input and output — a per-channel scale can land on the wrong axis — 9.1
- KV-cache quant ops must commute with quantize/dequantize — point it at arithmetic and the export succeeds, wrongly — 9.1
- The casting pass changes user input/output dtypes in place — feeding fp32 afterwards presents as garbage, not a type… — 9.1
- 0.3.0 lacks calibration-aware overflow protection; ignored_ops exclusions are available — 9.1
- 0.3.0 casting can overflow dynamic activations; calibration fix apple/coreai-optimization#117 is post-release — 9.1 🔇
- Historical pruning negative-axis defect; apple/coreai-optimization#45 fix is in 0.3.0 — 9.1 🔇
- 0.4.3 packed cat drops dim; apple/coreai-torch#41 merged September 25 outside that tag — 9.1 🔇
- Per-channel axis-0 int8 Linear weights return garbage on the macOS-27-beta GPU delegate — use per-block-32 there — 9.1
- The casting passes mutate the program and change user I/O dtypes — old callers feed fp32 and get garbage, not an error — 9.3
- Sub-byte nibble order is undocumented — the decode assumes MLX's low-first convention; verify on a known tensor first — 9.3
- Failure #16: IEEE -inf softmax masks compute wrong numbers on the ANE — use -40000.0 instead — 9.3
- Beta bug, not a fallback: per-channel axis-0 int8 Linear weights return wrong numbers on the macOS-27-beta GPU delegate — 9.3
Part 10
- Omit remove_functionalization and KV writes vanish: fluent, globally incoherent output that mimics bad quantization. — 10.README 🔇
- Sequential Core AI binds state arrays positionally; swapping state_names can produce fluent nonsense without an error. — 10.README 🔇
- A mismatched projection transpose exports cleanly and yields structurally shuffled activations with PSNR in the teens. — 10.1
- Causal mask shaped (1,q,1,k) instead of (1,k,1,q) runs without error but collapses SDPA PSNR to 15-30 dB. — 10.1 🔇
- ANE softmax with a negative-infinity mask can yield invalid results; use the finite sentinel — 10.1 🔇
- An M-RoPE that misses the exact cat([cos,cos]) then ::2 indexing pattern converts fine and outputs ~18 dB PSNR. — 10.1 🔇
- Caching new_k instead of key_rope stores pre-RoPE keys; shapes are identical but PSNR collapses to ~20 dB. — 10.1 🔇
- GELU substituted for SiLU runs like the original and is 20-30 dB off; activation functions are not interchangeable. — 10.1
- A non-contiguous tensor through the Python wrapper can produce wrong numbers rather than an error. — 10.1
- Historical 0.4.1 rewrite defect silently removed a broadcasting-significant axis move; preserve shipped-asset parity — 10.2 🔇
- Pipeline diagram: omit remove_functionalization and KV writes vanish silently. — 10.3
- input_names/state_names order is load-bearing: swap key and value and the model loads, runs, and emits fluent nonsense. — 10.3
- AIModel.load(path, None) trips MPSGraph errors, and a GC'd AIModel makes the load_function return garbage, not a crash. — 10.3
- Bundles missing chat_template.jinja silently fall back to raw completion; quality collapses and nothing warns. — 10.3
- Recipe line: remove_functionalization is mandatory - omit it and KV writes disappear (see 8.4). — 10.3
- Omit remove_functionalization and the KV cache never updates: fluent, incoherent output that mimics bad quantization. — 10.3
- Automatic rewrites can remove dead operations; validate the exact converted program and shipped asset — 10.3
- Skip chat_template.jinja in the bundle and runners fall back to raw completion; output quality quietly collapses. — 10.3
- Checklist: KV cache is in-graph mutable state - remove_functionalization is what keeps its writes alive. — 10.3
Part 11
- set() on a masked cooperative-tensor element does nothing and get() returns 0 - the wrong identity for max reductions. — 11.README 🔇
- The default reduction identity is zero even for max; three-argument row or column reductions clamp negative maxima. — 11.README 🔇
- Uninitialized cooperative tensors can look correct on the first launch and expose stale GPU register contents later. — 11.README 🔇
- A K loop left in the default multiply mode overwrites instead of accumulating, keeping only the last tile's product. — 11.1
- execution_simdgroups
, simdGroupsPerTG and descriptor (m,n) must agree; mismatch corrupts tiles like a numerics bug. — 11.1 - Masked-element set/get silently no-op or return zero, and a widely cited guard method name does not exist. — 11.1
- Verified: set() on a masked element is a no-op and get() returns zero; operator[] is entirely unchecked. — 11.1 🔇
- reduce_rows' identity defaults to sum_identity (zero) regardless of the operation you pass. — 11.1
- Naked exp() in a hand-written softmax overflows above ~88 fp32 / ~11 fp16; subtract the running max first. — 11.1
- TOC: cooperative tensors are not zero-initialised; they hold undefined register data. — 11.2
- TOC: the reduce_rows identity default silently computes max(0,row). — 11.2
- Skip the is_compatible_as_left_input check and an incompatible layout converts undiagnosed - wrong data, no error. — 11.2 🔇
- Cooperative tensors are not zero-initialised; accumulate into one unwritten and you add register garbage. — 11.2
- Uninitialised cooperative tensors often read 0 on a fresh pipeline and garbage on the next launch; it ships, then fails. — 11.2 🔇
- The reduce_rows identity default is zero for every operation, including max. — 11.2
- reduce_rows(S,rowMax,max) compiles and computes max(0,row); every all-negative row silently becomes zero. — 11.2 🔇
- The per-simdgroup if must not make run() non-uniform; divergent execution of the op is undefined behaviour. — 11.2
- Code comment: reduce_rows takes four arguments here - the identity is not optional in practice. — 11.2
- The three-argument reduce_rows in flash attention computes max(0,row); attention logits are frequently all-negative. — 11.2 🔇
- Code comment: four arguments; three would silently compute max(0,row). — 11.2
- Dispatch fewer threads than the execution scope declares and the op reads non-participating lanes; no validation exists. — 11.2 🔇
Part 12
- Six core-MLX traps where numbers go quietly wrong: scalar cache keys, frozen captured arrays, invisible NumPy mutations. — 12.README 🔇
- Affine gather_qmm on M5 leaves output rows unwritten (mlx#3856); they read back whatever the recycled MTLBuffer held. — 12.README 🔇
- Adapters train under a chat template serving may not reproduce (enable_thinking auto-defaults); quality quietly shifts. — 12.README 🔇
- custom_function silently zeroes gradients for arrays captured by closure. — 12.1
- Arrays captured by custom_function become constants; their gradients are silently 0.0 and training never updates them. — 12.1 🔇
- Under shapeless=True, Python arithmetic on x.shape freezes at trace time and later shapes compute with stale values. — 12.1
- shapeless compile bakes shape-derived arithmetic from the first call; new shapes silently reuse the frozen numbers. — 12.1 🔇
- apply(astype) casts packed uint32 quantized weights and integer params to bfloat16, destroying them; use set_dtype. — 12.1
- Writing through a NumPy view mutates MLX memory invisibly to autodiff; gradients come back wrong. — 12.1
- External mutation of MLX memory is invisible to autodiff: Apple's own demo returns the wrong gradient with no error. — 12.1 🔇
- Converting through NumPy breaks the autodiff chain and produces incorrect gradients even without in-place mutation. — 12.1
- DLPack hands over a pointer without synchronising; reading in torch before MLX's stream finishes yields wrong values. — 12.1
- Skip mx.eval before exporting a module and the .mlxfn captures the initialiser - it runs with fresh random weights. — 12.1
- A historical complex unary autodiff bug produced wrong gradients; affected release coverage remains unverified — 12.2
- MLX_SDPA_BLOCKS not a multiple of 32 silently corrupts attention every decode step on mlx <=0.32.0 (fixed in PR #3875). — 12.2 🔇
- math_mode relaxed/fast stops guaranteeing exp(-inf)==0; masked positions leak into softmax: plausible, wrong attention. — 12.2 🔇
- ensure_row_contiguous=False with raw linear indexing reads strided buffers wrong: right shape, wrong contents, no error. — 12.2 🔇
- Partially written custom-kernel outputs can retain recycled buffer contents; initialize or write every element — 12.2 🔇
- A kernel weight captured by closure gets no gradient under custom_function; pass tensors as arguments instead. — 12.2
- TOC: the register of quantized-matmul corruption bugs. — 12.3
- Seven quantized-matmul defects, five exclusive to M5-generation hardware; the register with statuses. — 12.3
- gather_qmm's unwritten rows aren't zeros: they hold recycled MTLBuffer contents, sometimes coincidentally plausible. — 12.3 🔇
- Decision-table flag: M5 affine MoE has one unreleased fix and one open bug; pad rows and keep K%64==0. — 12.3
- Training data renders under enable_thinking auto-defaults; serving with another template quietly degrades the adapter. — 12.6
- M5/A19 gather_qmm corruption in mlx#3856/#3887 affects big rows or ragged K through 0.32.2; #3922 fixes main. — 12.6
Part 13
- A missing or mismatched chat template yields fluent but degraded output blamed on the model — nothing checks it — 13.README 🔇
- KV quantization can leave stale caller references; speculative rollback can retain tokens that were never emitted. — 13.README
- A VLM factory processor-selection gotcha produces wrong output rather than an error — 13.1
- Dropped EXIF orientation feeds the model a rotated photo — wrong answers, no error; Apple fixed it in their own sample — 13.1
- An empty assistant placeholder passed to UserInput(chat:) closes the turn — garbage or empty output blamed on the model — 13.1
- Dropping LMOutput.State between turns drifts M-RoPE positions on VLMs — degraded multi-turn output, no error — 13.2
- A trailing empty assistant message closes the turn — fresh user turn or instant EOS on the raw UserInput path — 13.2
- The chat template is the contract and nothing checks it — mismatches produce fluent, degraded output — 13.2
- Unknown models default to .json tool format — a non-JSON model's tool calls stream into visible text, never firing — 13.2
- Restore plus instructions doubles the system prompt — fluent nonsense; saveCache also drops M-RoPE state (#443) — 13.2
Part 14
- Pass anything but the full monotonic position_ids and KV lands at the wrong cache slice — logits stay plausible — 14.README 🔇
- Boolean attention masks become additive 0/1 values in the bridge, leaving masked positions unmasked. — 14.README 🔇
- A position_ids max that isn't the last query position writes KV to the wrong offset — valid math, wrong cache — 14.1
- Skip the bf16→fp16 logit cast and the Swift runner's hard-coded Float16 view reports garbage argmax — no crash — 14.1
- allow_unknown_sources=True (default) invents scalar fp32 specs for unknown tensors — converts fine, can be badly wrong — 14.1
- Boolean attention masks are lowered as added, not selected — masked positions leak in, output stays plausible — 14.1
- General transposed convolution lowers to zeros — converts, runs, and outputs all-zero feature maps — 14.1
- mx.log2 and mx.log10 lower to natural log — every value wrong by a constant factor, no error — 14.1
- Store only the load_function and the AIModel gets GC'd — calls return garbage that looks like a conversion bug — 14.1
Part 16
- Some Spotlight metadata is searchable but unreadable — SpotlightSearchTool sees titles and invents the bodies — 16.README 🔇
- Skip the units instruction and the model answers 'distance: 4.2' in the wrong unit, confidently — quiet wrongness — 16.4
- The index is searchable but not readable — compact metadata matches queries but the model can't recover it — 16.4
- Session 246 verbatim: some Spotlight metadata is searchable but not recoverable — the model answers without it — 16.4 🔇
- .dynamic(GuidanceProfile) measured prompt-sensitive on 27.0 beta — the model may skip the search and answer from memory — 16.4 🔇
- The model reads titles and invents bodies — unreadable metadata becomes hallucinated content — 16.4
- Auto-rename binds fields to inputs on shape alone — a mask or pre-normalised batch is analysed cleanly and wrongly — 16.5 🔇
- A zero-L2 constant column turns normalisation into NaN/inf with no guard — the duplicates index is silently poisoned — 16.5
- Consolidated: field-to-input auto-rename fires on shape agreement alone — 16.5
Part 17
- A refused string generation returns success whose content is an apology; apps ship the apology as data — 17.1 🔇
- In string mode a refusal is a successful response; the apology string flows into your pipeline as real content — 17.3 🔇
- A throwing subject(from:) lets refusals abort samples; aggregate eval scores silently exclude the refused cases — 17.3 🔇
- coreai-models has zero EXIF or orientation handling; rotated camera photos silently produce wrong vision results — 17.5
- Orientation and coordinate conventions are now your job; getting them wrong yields plausible but wrong vision output — 17.5
- CIImage(contentsOf:) applies EXIF orientation, CGImageSource does not; the same JPEG preprocesses two different ways — 17.5
Empty output / no-op¶
Runs and returns nothing where content is expected — nil, empty results, operations that quietly do nothing.
Part 1
- A tool-only response stream can finish with no partials; waiting for the first token leaves the spinner stuck. — 1.README 🔇
- A tool-only turn can yield no streaming partials; a spinner tied to partials never updates — 1.1 🔇
Part 2
- Skipping the searchableItems completion handler leaves Spotlight waiting forever without an error or timeout. — 2.README 🔇
- A tool-call-only turn ends the stream after zero partials — spinner UIs waiting on a first partial hang forever. — 2.1 🔇
- Python's contents.value returns None for a missing key where Swift throws — ported code silently reads null. — 2.2
- Heading: a stream can finish having yielded zero snapshots. — 2.2
- for try await can complete with zero iterations on a tool-call-only turn — first-snapshot spinners hang, unwraps crash. — 2.2 🔇
- Tool-only turns are normal in agentic sessions — zero-snapshot streams occur in routine operation; design for them. — 2.2
- A turn whose entire output is a tool call streams nothing — streamResponse completes without yielding one partial. — 2.3 🔇
- Device-tested: unlabelled attachments still reach tools; the hazard is no stable identity for ImageReference lookup. — 2.3 🔇
- Skip calling searchableItemsHandler on any path and Spotlight waits forever — no error, no visible timeout, no results. — 2.4 🔇
- Your searchableItems delegate can be wired, compiled, and simply never called — verify it fires before building on it. — 2.4 🔇
- A ResponseStream can end with zero partials on tool-call turns — multimodal turns hit this disproportionately. — 2.5 🔇
- Labels are identity, not a gate; omit one and identity lookups resolve to nil. — 2.5 🔇
- Unknown image labels resolve to nil instead of producing a matching image — 2.5 🔇
- The DETR postprocessor suits set-prediction only — with anchor-based YOLO, decode returns [] and you 'detect nothing'. — 2.5
- Modifiers apply outside-in — composed in the obvious order, summarizeHistory can never fire. — 2.6
Part 3
- summarizeHistory is a no-op on tool-output continuations — the guard fails and nothing records that it skipped. — 3.1
- Heading: the composed example in Apple's README can never fire. — 3.1
- summarizeHistory fires only when the last entry is a .prompt — after tool turns it silently skips; Apple's test says so. — 3.2 🔇
- Heading: the composition rule — and why Apple's own examples never fire. — 3.2
- rollingWindow(10) before summarizeHistory(threshold:10): 10>10 is false forever — summarisation can never run. — 3.2 🔇
- Contents entry: every composed example in the repository is inert. — 3.3
- On tool-output continuations the summarise guard fails and the modifier returns — no log, no observable difference. — 3.3 🔇
- Heading: every composed history-modifier example in the repository is inert. — 3.3
- An inert composition is indistinguishable from a working one — until contextSizeExceeded starts landing in production. — 3.3 🔇
Part 4
- First-token spinners can hang two ways at .deep — tool-call-only turns yield zero partials, and reasoning runs unseen. — 4.1 🔇
- Legal SSE data: lines without a following space are silently dropped by the parser — 4.2 🔇
Part 5
- A turn that is only a tool call completes streamResponse with zero partials; spinner-until-first-partial UIs hang… — 5.1 🔇
- Looking up a missing GeneratedContent key returns None without an error — 5.2
- A tool call() that never returns leaves the Swift continuation unresumed — the session hangs forever, no timeout, no… — 5.2
- pytest collects test_memory_stress.py and runs nothing — it defines no test_ functions; invoke it with python directly. — 5.2
Part 6
Part 7
- Outputs you pre-allocate views for are updated in place and omitted from the returned Outputs — lookups come back nil — 7.1
- An output with a provided view is updated in place and not included in returned Outputs — reading it there finds nothing — 7.1 🔇
- vocabType defaults differ (.raw vs .byteLevel) — the mismatch over-constrains the grammar and generation yields nothing — 7.4
- Detector postprocessing returns an empty array for malformed output ranks and lengths, indistinguishable from a valid… — 7.5 🔇
Part 10
Part 12
- DWQ on mxfp4/mxfp8/nvfp4 or 8-bit affine runs, prints losses, and writes a checkpoint quantized identically to input. — 12.3 🔇
- A missing valid.jsonl only warns: a full run completes with no validation curve and no overfitting signal. — 12.6
Part 13
- Tool-only responses emit zero .chunk events (.toolCall then .info) — a spinner keyed to first text hangs forever — 13.2
- A tool Output that fails to encode becomes '{}' silently — the model reasons over an empty result, no error — 13.2
- trimPromptCache returns 0 instead of throwing on untrimmable caches — the trim quietly does nothing — 13.2
- Tool calls with an unrecognised name are dropped silently — the tool never fires, no error surfaces — 13.3
- Re-serialize before the $defs rewrite and escaped slashes stop the prefix matching — the rewrite silently no-ops — 13.3
Part 16
- Entity plumbing the screenshot path never consults costs weeks and changes nothing; per-row ids also lose rows — 16.README 🔇
- The sample forwards preset.attributeOptions unchanged and progressiveLongDictation omits .audioTimeRange — no merge data — 16.1
- Query bestAvailableAudioFormat before assets install and it silently returns nil — ?? default hides the ordering bug — 16.1 🔇
- Code comment: AnalyzerInputConverter returns nil unless assets are already installed (§5.5) — 16.1
- Without audio time ranges strategy A silently degrades to append-only — the replace-by-range merge never fires — 16.1
- Conformance is not donation — entities never explicitly indexed never appear, however correct the types — 16.2
- Conflict with the doc shape: thread 838329 reports the NSUserActivity route produced no callbacks at all — 16.3
- Entity plumbing for the screenshot request class is never consulted — weeks of work, zero callbacks (thread 837249) — 16.3
- A non-schema entity never resolves for hand-off — the pipeline quietly yields nothing — 16.3
- Reported, unconfirmed: the NSUserActivity route producing no awareness callbacks at all — 16.3
- 'Describe this scan' is answered from a screenshot, not ScanEntity — your entity layer never participates — 16.3
- A property without indexingKey: is simply not in the index — searches and the model see nothing for it — 16.4
- Wire the delegate correctly and on tested 27.0 betas nothing ever invoked it — no throw, no log; hallucination continues — 16.4
- An unmapped entity property is simply absent — no error; the field never exists downstream — 16.4
- The hydration delegate is never called (field-reported) — bodies stay unrecoverable and nothing logs — 16.4
- Keras 3 before 2f39056 yields generic tensor names and an empty layer list — a successful run that analyses nothing — 16.5 🔇
- Without umap-learn the report builds successfully with no projection columns — Symphony shows an empty scatter — 16.5
- Consolidated: Keras 3 without 2f39056 classifies every layer UNKNOWN — empty analysis, no error — 16.5
Part 17
- A response stream can finish with zero text partials when the model emits only a tool call; unguarded UIs show nothing — 17.1 🔇
- A stream can finish having yielded zero text partials when the model emits only a tool call — 17.2
- contiguousElements returns nil once specialization prefers a non-contiguous layout; data you expected is not there — 17.5
- Xcode's Source Viewer stays empty unless debug metadata was embedded in the .aimodel at export time — 17.5
Truncation & limits¶
Input or output silently truncated or capped — context windows, response sizes, token budgets.
Part 2
- maximumResponseTokens stops output mid-sentence as a valid Response — no throw and no wasTruncated flag exists. — 2.1 🔇
- Do not hardcode 4096 — budgeting below the real window over-compacts and quietly degrades answers; read contextSize. — 2.6
- maximumResponseTokens truncates mid-sentence without error — the response arrives valid, just cut off. — 2.6
Part 3
- A hardcoded 4096 under a 32K PCC window compacts eight times too often and summarises away context the model could use. — 3.1 🔇
- @Generable schemas ride along with every request but appear in no transcript entry — unbudgeted, they skew your math. — 3.1
- Apple: limiting tokens can produce incomplete responses like 'A cat is a small.' — use only to curb verbosity. — 3.2
Part 6
- JSONLoader logs malformed rows to OSLog and skips them; a corrupt dataset shrinks and still reports a clean aggregate. — 6.README 🔇
- targetCount is a total: 13 seeds + 100 yields 87 new samples, and a target below your current count generates zero… — 6.README 🔇
- A 100-row file with 63 undecodable rows loads 37, runs cleanly and reports a green aggregate; only OSLog records the… — 6.1 🔇
- TOC: targetCount counts the samples you already have — generation runs under-deliver or produce nothing. — 6.3
- targetCount is the total dataset size including seeds, not a count of new samples to generate. — 6.3
- With 800 samples, targetCount: 200 adds nothing and exits cleanly; 13 seeds + 1000 yields 987 new — never a thousand. — 6.3 🔇
- JSONLoader reads JSON or JSONL and OSLog-and-skips malformed entries — your dataset silently shrinks on read. — 6.3 🔇
Part 7
- Mistral's synthetic tool-call close marker is a newline — multi-line tool-call JSON is cut at the first line break — 7.4
- maximumResponseTokens counts hidden thinking — a small cap can end the turn mid-
with no response at all — 7.4
Part 13
- ChatSession's default processing resizes every image to 512×512 — detail silently lost unless you override — 13.1
- Images are resized to 512×512 by the default processing unless you say otherwise — 13.2
- Inputs beyond maxPositionEmbeddings are truncated with only a console warning — never an error — 13.2
- If thinking exhausts the budget before , phase 2 is skipped entirely — no structured output at all — 13.3
- Budget-exhausted guided generation succeeds with truncated JSON — incompleteOutput is metadata, not a thrown error — 13.3
Part 16
- Cancel the display task and the transcriber's final updates go unread — every recording's last phrase lost, no error — 16.README 🔇
- Contents: the cancellation shield — the guard against losing each recording's final phrase — 16.1
- Code comment: without the shield you lose the tail of every recording — 16.1
- The cancellation shield: stop reading at cancel time and the final updates — the recording's tail — are lost — 16.1
- Code comment: the shield is an unstructured Task so display outlives cancellation and reads the final results — 16.1
- PFA skips layers with fewer samples than features, emitting only a warning — the layer is absent from the recipe — 16.5 🔇
- Consolidated: PFA drops unanalysable layers with only a warning — 16.5
Ignored input¶
A parameter, flag, option, file or annotation is silently ignored, dropped, or overridden.
Part 1
Part 2
- @Guide(.anyOf) does not reliably constrain output — out-of-set values parse cleanly and your switch hits default. — 2.README 🔇
- Contents entry: @Guide(.anyOf) does not constrain generation. — 2.2
- Heading: .anyOf does not constrain generation. — 2.2
- The model emits values outside your .anyOf set; nothing throws, the String parses, and switches fall to default in prod. — 2.2 🔇
- Python @fm.generable('description') stores the description and never sends it — the model never sees it. — 2.2
- Python respond(generating:) drops options= on the floor — temperature, sampling, max tokens have no effect; evals lie. — 2.2 🔇
- .anyOf on tool arguments is confirmed broken — a three-city constraint got called with 'Beijing'; validate in the tool. — 2.3 🔇
- A CustomStage conforms and is accepted, but the 27.0-beta pipeline never routes items through it — measured no-op. — 2.4 🔇
- permissiveContentTransformations does not apply to @Generable — adopting guided output silently drops permissive mode. — 2.6
Part 3
- Endpoint building recognises only 'v1' — any other version path silently gets /v1/chat/completions appended. — 3.3
- A call-site GenerationOptions(toolCallingMode:) silently overrides the profile's conditioned exit — loop or no tools. — 3.4 🔇
Part 4
- buildURLRequest recognises only 'v1' in the path — other version paths get the wrong endpoint; live defect FB23837262. — 4.1
- Contents entry: the URL-versioning defect, and the workaround that works. — 4.2
- Heading: the URL-versioning defect, and the workaround that works. — 4.2
- LFM2.5 ignores in-context Hermes tool-call instructions and emits its trained dialect — the training prior wins. — 4.2
- Comparison table: on Core AI only temperature reaches the engine — seeds and other sampling options are dropped. — 4.2
- The shipped executor never reads contextOptions, id, or metadata — ContextOptions(reasoningLevel:) does nothing. — 4.3
- Heading: the silent failure hiding in every transcript-conversion switch — unhandled entries just disappear. — 4.3
- Catch-all defaults in transcript converters drop unhandled entries — the request goes out short and the model answers. — 4.3 🔇
Part 5
- A schema flag that fails to apply still yields prose on stdout with exit 0; jq errors lines later, blaming the wrong… — 5.README 🔇
- The Python typed-response path drops options, so temperature, sampling controls and token caps do not reach Swift. — 5.README 🔇
- fm respond writes prose to stdout when a schema isn't applied, exit 0; jq errors later naming the wrong culprit. — 5.2 🔇
- In the generating=Cat branch of respond, your options are dropped. — 5.2
- respond(generating:options:) silently discards options — session.py:473 calls _respond_with_schema without them. — 5.2 🔇
- top_k/top_p/seed are serialised as strings the Swift side fails to cast — sampling is never assigned; seeds do nothing. — 5.2 🔇
- Optionality is substring-sniffed from the type string — 'int | None' fields silently become required. — 5.2
- is_optional is 'Optional' in str(type): int | None never matches, and Optional[int] stops matching on Python 3.14. — 5.2 🔇
- The @fm.generable description is stored and never read — the type-level description never reaches the model. — 5.2
- @fm.generable('desc') stores _generable_description; nothing passes it into the schema — grep finds zero readers. — 5.2 🔇
- value(int, for_property:) never coerces raw values — the coercion helper is dead code and a JSON string stays a str. — 5.2
- Reproducible sampling is greedy-only in Python — random-sampling params, seed included, never survive the bridge. — 5.2
Part 6
Part 7
- .chunked KV strategy is accepted and silently falls back to the static cache — it is not implemented — 7.3
- VLM sampling is hard-coded to temperature 1.0 / topK 1 — the GenerationOptions temperature you pass never reaches it — 7.4
- --kv-cache-strategy chunked is accepted but unimplemented — you silently get a fixed-size cache — 7.4
- The stopTokenIds parameter is dead — values you pass are never consulted by the engines — 7.4
Part 8
- Unmatched ExternalizeSpec warns, never raises — a typo ships a slower model; assert on composite_declaration in the IR — 8.README 🔇
- ExternalizeSpec target_class must be RMSNormImpl — pointing at the RMSNorm wrapper silently matches nothing — 8.1
- An unmatched externalization target only warns and converts without applying the requested boundary — 8.1
- clone()/contiguous() lower to identity — barrier-by-clone silently does nothing against the buffer-clobber bug (#11) — 8.2
- A typo in composite_attrs or target_class is a UserWarning, not an error — filtered warnings ship a slower model… — 8.2 🔇
- Externalize RMSNormImpl, not RMSNorm — the wrapper class silently matches no submodule — 8.2
- Externalization's four silent failures — unmatched specs and attr typos warn or say nothing and quietly drop the… — 8.2
- torch.cond branch subgraphs never receive your registered custom lowerings — a pinned strict-xfail converter bug — 8.3
Part 9
- A non-divisible block size leaves a layer at full precision and removes its fake-quant node after a warning. — 9.README 🔇
- A non-divisible palettization group size disables the module permanently and removes its parametrization. — 9.README 🔇
- module_type_configs keyed by the string 'torch.nn.Linear' silently matches nothing — use the class object — 9.1
- A block size your weight isn't divisible by leaves the layer uncompressed, with only a log line — 9.1
- Block-size mismatch is caught internally and swallowed — the fake-quantize disables itself and the layer ships… — 9.1 🔇
- Diffusion path swallows quantization failures with a warning — you can ship a full-precision model believing it… — 9.1 🔇
- shape[axis] % group_size must be 0 — a non-dividing group size leaves the layer unpalettized with only a warning — 9.2
- Realized sparsity rounds down — an unreachable channel target can round to zero pruning — 9.2
- floor(8 channels x 0.1) = 0: the layer is untouched, no warning — your '10% sparse' model is 0% sparse in narrow layers — 9.2 🔇
- prepare() succeeds while mis-sized layers were never compressed — the model ships bigger than your release notes say — 9.2 🔇
- 'torch.nn.Linear' has dots so it passes the syntactic check and then matches nothing — genuinely silent — 9.2
- A block size the weight doesn't divide by leaves the layer at full precision — a warning is the only trace — 9.3
- The fake-quantize logs 'Skipping quantization' and permanently disables itself — graph mode then removes the node — 9.3 🔇
- Failure #1: non-dividing block_size leaves the layer uncompressed; only one logger.warning marks it — 9.3
- Failure #13: an MLX layer whose last dim doesn't divide group_size is silently skipped by the quant predicate — 9.3
- Failure #17: diffusion components that fail quantization are swallowed with a warning — check file size on disk — 9.3
- Diffusion quantization failures are swallowed (export/compiler.py) — cross-check on-disk size against numel x bits/8 — 9.3 🔇
Part 10
- CLI --n-bits/--group-size hit both encoders uniformly, silently overriding the recipe's asymmetric per-encoder settings. — 10.1
- Compression succeeds while log-only skips leave layers untouched; the asset is less compressed than you configured. — 10.2 🔇
- Short type keys like torch.nn.Linear silently match nothing; the config is accepted and the layer is quantized anyway. — 10.2
- Graph-mode op names are global, eager-mode are module-qualified; a pattern from the wrong mode matches no layers at all. — 10.2 🔇
- module_type_configs keys must be full internal paths; short names silently match no modules. — 10.3
- Compression completes while quietly skipping layers; the shipped asset is bigger and less quantized than configured. — 10.3
- Compiling with --expect-frequent-reshapes does not make the runtime hint safe; both variants crash - load-time matters. — 10.3
- KV strategy .chunked is accepted by the API and does nothing. — 10.3
Part 12
- mlx-lm applies a chat template you didn't pick, and --use-default-chat-template is a no-op in generate; six traps total. — 12.README 🔇
- MLX_ENABLE_TF32 is read on first use - set after your first matmul it silently does nothing; matvec shapes stay fp32. — 12.1
- Layers whose input dim doesn't divide the group size are silently left in full precision. — 12.3
- A Linear not divisible by group_size is silently kept full-precision: your 4-bit model is 4-bit except awkward layers. — 12.3 🔇
- --use-default-chat-template is accepted by mlx_lm.generate and does nothing. — 12.4
- mlx-lm applies a chat template in cases where you expected yours or none; --use-default-chat-template is a no-op. — 12.4
- Several sampler parameters are accepted and never reach the sampler; outputs don't change. — 12.4
- stream_generate silently drops unknown kwargs; a typoed sampler argument changes nothing and raises nothing. — 12.4
- tools passed to a model that can't call tools only logs a warning; the response just never contains tool calls. — 12.5
- --clear-cache-threshold parses fine and is silently ignored; it never reaches the trainer. — 12.6
- --clear-cache-threshold never reaches the trainer; memory behavior is unchanged no matter what you pass. — 12.6
- run() silently discards the training_callback you pass in; no metrics hooks ever fire. — 12.6
- LoRA target keys use exact set membership; a glob or regex pattern silently selects zero layers. — 12.6
- Byte-identical greedy outputs mean the adapter never loaded: lora_b starts at zero, so unloaded equals the base model. — 12.6
Part 13
- Resolver patches are mostly inert: only reasoningConfig is consumed; extraEOSTokens and toolCallFormat change nothing — 13.README 🔇
- generation_config.json eos_token_id replaces rather than unions — earlier stop tokens silently discarded — 13.1
- Memory.cacheLimit is one process-wide value and libraries set it behind your back — your setting can be silently stomped — 13.1
- seed is inert at temperature 0 — greedy decoding never consults the RNG — 13.2
- At temperature 0 every sampler knob is ignored; topP 1.0 and topK 0 are also no-ops — decorative config fields — 13.2
- Stop-token step 2 replaces rather than unions (matching Python) — earlier EOS ids silently discarded — 13.2
- kvScheme overrides kvBits and typo'd scheme strings are silently ignored — no quantization, no message — 13.2
- RotatingKVCache.toQuantized() is never called — rotating layers silently stay fp16 whatever kvBits says — 13.2
- Detection-script print: layers whose cache type can't quantize stay fp16 silently despite kvBits — 13.2
- Sample output: 36 layers will stay fp16 silently under the requested kvBits — 13.2
- progressHandler is ignored for local-directory loads — no progress events ever arrive on that path — 13.3
- The SDK never gates image input on .vision — without the adapter's check, images go to text-only models silently — 13.3
- TranscriptConverter drops entries with only debug-level logs — transcript content quietly missing from the prompt — 13.3
- Resolver patches are mostly inert — only reasoningConfig is consumed; everything else compiles and changes nothing — 13.3
- GrammarTokenizer registers exactly one stop token with xgrammar — other stop tokens are not enforced — 13.3
- The bridge's stopTokenIds parameter is dead — accepted, never forwarded — 13.3
Part 16
- Unsupported phoneme symbols are silently ignored — validate against supportedPhonemes(locale:) at build time — 16.1
- Four of six failure rows give working transcription that ignores your vocabulary — invisible unless you speak jargon — 16.1 🔇
- Excessive interaction donations are silently ignored — over-donate and the surplus just disappears — 16.2
Part 17
- Omit .label() on an image Attachment and tools never see the image; the model improvises with no diagnostic — 17.1 🔇
- permissiveContentTransformations only applies to string output; guided generation still runs the default guardrails — 17.1 🔇
- .anyOf produces no error and no warning and does not constrain; tools receive arguments outside their domain — 17.1 🔇
- The Python SDK stringifies top_k/top_p/seed so Swift ignores them; seeded evaluation runs are not reproducible — 17.1
- ba-package package exits 0, the .aar downloads and reports available, and the FM runtime never uses it — 17.2 🔇
- The @Guide(.anyOf:) guide does not do what it says: the constraint is accepted and silently ignored — 17.2
- Apple reproduced it: @Guide with .anyOf compiles and runs but generation ignores the allowed-value list — 17.2 🔇
- Set permissiveContentTransformations then call respond(generating:) and the setting is inert; guardrails run as usual — 17.3 🔇
- Palettization silently skips layers incompatible with the configured granularity; the model ships partly uncompressed — 17.5
- Incompatible granularity disables palettization for the layer with only a log message — 17.5
- Running python from the coreai-torch clone shadows installed 0.4.1 with the 0.4.0 egg-info; exports silently regress — 17.6 🔇
Stale state¶
Stale or cached data served; invalidation that did not happen (or happened unexpectedly).
Part 2
- Tool parameters are computed once at session init and never re-read — late-loaded .anyOf data never reaches the schema. — 2.3 🔇
- .preserveTranscript can leave a partially generated last entry — transcript repair is on you before continuing. — 2.3 🔇
- preserveTranscript can leave a half-generated entry in history — later turns build on the corrupted tail. — 2.6
Part 3
- trimKVCache may retain one token fewer than asked — prefill from the requested offset and model state silently diverges. — 3.1
- A SkillActivations built in a view body resets every render — skills silently deactivate and re-activate in a loop. — 3.3 🔇
- The baton lands on the next request — the profile that called the tool usually still finishes the current turn. — 3.4
- .preserveTranscript may leave the last entry partially generated — put the transcript back in order before continuing. — 3.4 🔇
- Heading: the consent nobody answers — a pending proposal that never resolves. — 3.4
- A pending approval proposal with no resolution path leaves the model believing a question is outstanding, forever. — 3.4 🔇
- A child session over the parent's model instance corrupts the parent's KV state — give the consultant its own model. — 3.4
Part 4
- Models differing only in URLSessionConfiguration are cache-equal — the second silently inherits the first's transport. — 4.README 🔇
- The executor cache is keyed on Configuration, not your model value — equal configs silently share one executor. — 4.2 🔇
- Configuration's == deliberately excludes the URLSession — your timeout config can silently be the other model's. — 4.2 🔇
- MLX executors share a model-ID cache key despite differing capabilities; isolate IDs when comparing capability sets — 4.2 🔇
- A hand-written == ignoring a behavioural field makes the framework return the wrong cached executor. — 4.3 🔇
- Contents entry: the urlSession that isn't in the cache key. — 4.4
- Heading: the urlSession that isn't in the key. — 4.4
- Configs differing only in URLSession are cache-equal — a 600 s timeout silently becomes the default, proxies skipped. — 4.4 🔇
Part 6
- TOC: sessionProvider is a factory that may be called again mid-run, discarding conversation-held state. — 6.3
- sessionProvider is a factory: on context exhaustion the run silently swaps in a fresh session mid-generation. — 6.3
- After a mid-run session swap, conversation-held rules ('no repeats') vanish — the dataset's second half goes… — 6.3 🔇
Part 7
- No reset() exists — a new conversation silently continues on whatever KV the last one left in the state — 7.3
- Noema tracks fedTokens and prefix-checks before reuse — anything else risks decoding against another conversation's KV — 7.3
- The ANE in-graph KV-write crash corrupts the compile cache — later loads fail ENOENT until you delete cache entries — 7.3
- Two models built from the same URL and settings share one engine and KV cache — the second session resets the first — 7.4
- Diffusion filename fallback can select a stale component when old and new exports coexist; ship an explicit schema-0.2… — 7.5 🔇
Part 10
- Stateful transforms reset KV caches between Python inference calls; pass caches as explicit inputs and outputs — 10.1 🔇
- An in-place mutation of a forward() input becomes hidden converted-model state; there is no flag to opt out. — 10.2 🔇
Part 12
- Arrays captured by an mx.compile closure freeze at trace time; later updates never reach the compiled function. — 12.1
- state[0] = new value has no effect on a compiled function that captured it; it keeps returning the traced constant. — 12.1 🔇
- mlx_lm.benchmark empties the tokenizer's EOS set in place; reuse that tokenizer and generation never stops. — 12.4
- ChunkedKVCache and ConcatenateKVCache break the server prompt cache's trim assumptions; hits can return mismatched KV. — 12.4
- The server's prompt-cache reuse can return KV that doesn't match your tokens, mixing another prompt's context in. — 12.4
- The Swift port carries its own KV-cache bugs; Mac apps hit them through cache reuse. — 12.4
Part 14
Part 16
- Entities stay registered until you remove them — no TTL; a missed removal leaves stale suggestions indefinitely — 16.2
- SnippetIntent may re-run; cached state renders stale UI — the tapped toggle doesn't move and nothing errors — 16.2
- There is no TTL — registered relevance donations persist until you explicitly remove them — 16.4
- Stale index entries survive deleted content — Spotlight keeps serving what your app already removed — 16.4
Part 17
- With .preserveTranscript a failed turn leaves a partial entry; later turns treat truncated output as context and degrade — 17.3 🔇
- Uploading a fixed model reaches no users until the revision pin advances; the catalog keeps serving the old artifact — 17.6
Data & artifact loss¶
Silent loss or overwrite of data or build artifacts — purged assets, dead bookmarks, unrebuildable builds.
Part 2
- summarizeHistory condenses everything into one .prompt entry — attachments vanish and later image answers are invented. — 2.5 🔇
- rollingWindow is a naive suffix(n), not transcript-aware — it cuts between a prompt and its response. — 2.6
Part 3
- Summarisation renders segments to text first — structured content and attachments are dropped without comment. — 3.1 🔇
- Policy table: rollingWindow is known-buggy — it can orphan a response — and invalidates the cache when it fires. — 3.1
- Policy table: summarizeHistory collapses history to one entry, losing tool structure, and totally invalidates the cache. — 3.1
- Apple's own test: rollingWindow's naive trim orphans a response — 'in practice it crashes partway through.' — 3.2 🔇
- Contents entry: rollingWindow splits prompt/response pairs — and Apple knows. — 3.3
- Heading: rollingWindow splits prompt/response pairs — and Apple knows. — 3.3
- Apple's test comment verbatim: the naive trim orphans a response and 'in practice it crashes partway through.' — 3.3 🔇
- The summariser never sees instructions, structured content, or images — it compresses a chat it cannot understand. — 3.3 🔇
Part 4
- Metadata and usage updates replace whole snapshots; omitting a previously sent key deletes it. — 4.README 🔇
- summarizeHistory condenses everything to one .prompt entry — .toolCalls entries are destroyed; roll your own modifier. — 4.1
- A chunk carrying both tool_calls and content loses the content — the else-if drops interleaved text; nothing throws. — 4.2 🔇
- Heading: wholesale, not additive. — 4.3
- updateMetadata events are wholesale snapshots — send fewer keys and the missing ones are removed; re-emit everything. — 4.3 🔇
Part 7
- .persistent means until the next OS update — every point release purges all specialized assets and users repay the stall — 7.2
- A cache bookmark pins nothing — the entry can be deleted underneath it on OS update or storage pressure — 7.2
- bookmarkData is a pointer, not the model — the system deletes the entry underneath it and resolving just returns nil — 7.2 🔇
Part 9
- Eager-only KMeansPalettizer.finalize() frees the dense float weights — there is no undo — 9.2
- finalize() discards float weights with no warning — if prepare() mutated your only copy, the float model is gone — 9.2 🔇
Part 10
- Provenance of the incident that made every coreai-torch 0.4.0-converted asset permanently unusable. — 10.2
Part 12
- --auto-setup disables the Thunderbolt Bridge on every machine - a destructive network-config change on each node. — 12.5
- Resuming restores weights only; Adam moments and schedule position are silently reset to zero. — 12.6
Part 13
- Bare HubClient caches weights in Library/Caches — iOS purges it under storage pressure and multi-GB models vanish — 13.1
- PhotosPicker's receivedFile.file lives in a temp dir deleted after the closure — copy it out or the URL dies — 13.1
- Parallel xctest workers race on the shared HuggingFace cache — intermittent corruption that looks like a checkpoint bug — 13.1
Part 14
- _write_tokenizer rmtree's an existing destination — a re-run silently destroys whatever was there — 14.1
Part 15
- A stored bookmark quietly stops working — purge or invalidation makes resolve return nil, not an error — 15.1
- bookmarkData doesn't pin the entry; resolvingBookmark returns nil, not an error — failure lands in an else branch — 15.1 🔇
- Code comment marks the silent branch: a well-formed bookmark whose entry is gone resolves to nil — 15.1
- Every OS update purges all specialized assets regardless of cache policy — they are OS-version specific — 15.1
Part 17
- summarizeHistory destroys tool-call metadata; swapping it in for hand-rolled compaction loses tool context — 17.1
- finalize(backend: CoreAI) frees the original dense weights in place; without a checkpoint the source model is gone — 17.5
- Audit before you repack: coreai-build package destroys the producer metadata that identifies bad exports — 17.6
- AIModel(resolvingBookmark:) returns nil, not an error, once an OS update purges the cached entry — 17.6
- Stale bookmarks return nil while malformed ones throw; the nil path fires for every user after every OS update — 17.6 🔇
- The nil-return branch is the path every user takes after every OS update; handle it by re-specializing — 17.6
- Bookmarks-specific trap: bookmark data does not pin the cache entry it references — 17.6
- Bookmark data pins nothing; only a live AIModel pins its cache entry, so storage pressure can purge under a bookmark — 17.6
Compiles but unavailable¶
Builds fine, then fails or degrades at runtime for some users — OS floors, device eligibility, missing assets, entitlements.
Part 1
- SwiftPM from: 1.0.0 excludes the package's prerelease tags; pin an exact beta or revision — 1.1
- MLXFoundationModels compiles to an empty library with the SDK 26 version gate — 1.1 🔇
- Constructing PrivateCloudComputeLanguageModel without its entitlement is a fatalError crash, not a catchable throw. — 1.2 🔇
Part 2
- Contents entry: backends that sample on the GPU expose no logits, so guided generation is lost there. — 2.2
- Heading: the logits problem — the fastest backend can lose guided generation. — 2.2
- Engines that sample on the GPU never expose per-step logits — guided generation there is impossible, not degraded. — 2.2 🔇
- OCRTool is unavailable on watchOS and tvOS; BarcodeReaderTool supports watchOS, so gate OCR paths separately — 2.3
- Symbol table: OCRTool has no watchOS row; its Arguments/Output are absent from the captured Vision interface. — 2.3
- Model availability is not tool availability — every documented check passes while SpotlightSearchTool fails to init. — 2.4 🔇
- On Linux the Python SDK buffers whole responses — streaming arrives in one burst — and @Generable is Darwin-gated. — 2.5
- Image support needs the macOS 27 SDK at build time — a wheel built without it permanently lacks Attachment. — 2.5 🔇
Part 3
- BYO models on GPU-pipelined bundles lose @Generable — guided generation needs logits those engines never expose. — 3.1
- Backend table: @Generable is unavailable on GPU-pipelined Core AI bundles — no logits, no constrained decoding. — 3.4
- Heading: the constraint that decides your backend — @Generable needs logits. — 3.4
- GPU-pipelined bundles sample on-GPU and never surface logits — the fastest backend forfeits guided generation. — 3.4 🔇
Part 4
- PCC without its entitlement fatalErrors past do/catch; availability ignores quota; reasoning tokens eat the 32K unseen. — 4.README 🔇
- GPU-pipelined Core AI returns no logits so @Generable cannot work — variant:nil auto-detect hides which engine you got. — 4.README 🔇
- PCC needs Xcode 27 plus a physical device on 27.0+ — it does not work in the Simulator. — 4.1
- Heading: the missing entitlement does not throw. — 4.1
- Missing the managed PCC entitlement produces a fatalError — do/catch never runs; community-reported, thread 831998. — 4.1 🔇
- Community: watchOS 27 alone is not enough for PCC — the Watch must pair to an iPhone with Apple Intelligence on. — 4.1
- Heading: the Simulator does not run PCC. — 4.1
- Heading: guided generation can disappear. — 4.1
- Moving off PCC to a fast local backend can cost you @Generable — GPU-pipelined engines expose no logits. — 4.1
- Contents entry: the logits constraint — why the fastest backend loses @Generable. — 4.2
- On Linux streamResponse still compiles and yields partials — but all at once, when the request completes. — 4.2
- Factories load via NSClassFromString — skip linking MLXLLM and there is nothing to find; loading fails at runtime. — 4.2
- Community 4B loads hit GPU JIT scratch-disk or ANE warmup failures; the reported AOT GPU path worked — 4.2
- Heading: the logits constraint — why the fastest backend loses @Generable. — 4.2
- Verified on 27.0 beta: hybrid/SSM bundles run behind LanguageModelSession, but pipelined engines expose no logits. — 4.2
- On non-Darwin the executor buffers the entire response — 'streaming' delivers everything at once at completion. — 4.3 🔇
- Verified at CoreAILanguageModel.swift:860 — GPU-pipelined bundles report guided generation unsupported; no logits. — 4.4
Part 5
- Image support is compiled in or out by the build machine's macOS SDK; users learn only when an image prompt fails. — 5.2
- A wheel built where SDK detection returns None or <27 omits image support; nothing at runtime says so until a prompt… — 5.2 🔇
Part 7
- Default macOS pipelined engine reports supportsLogits=false — @Generable throws unsupportedCapability at generation time — 7.README
- Core AI code paths vanish from Simulator builds — the 27.0 simulator SDK ships no CoreAI framework; device SDKs do — 7.1
- NDArray.RawView's Metal-buffer initializer is unavailable on watchOS — 7.1
- Float16 doesn't exist on Intel macOS — Apple's own code fatalErrors, so fp16 models crash x86_64 builds outright — 7.1
- AsyncValue's unsafe Metal-buffer initializer is unavailable on watchOS; await access while compute is in flight — 7.1
- ComputeStream(commandQueue:) is absent on watchOS; encoded inferences on one stream serialize by read/write dependencies — 7.1
- AOT compiles only for Apple-Intelligence-capable devices (A17 Pro+, M1+) — older hardware isn't covered — 7.2
- ComputeStream(commandQueue:) does not exist on watchOS — 7.3
- The second async-value initializer is likewise absent on watchOS — 7.3
- AsyncValue's NDArray initializer is unavailable on watchOS — 7.3
- Grammar-constrained decoding needs logits — @Generable and forcedContinuation are unavailable on the GPU-pipelined path — 7.3
- Missing tokenizer/ falls back to a HuggingFace Hub fetch — instant on your Mac's cache, a network request on user… — 7.4 🔇
- Guided generation and the fastest engine are mutually exclusive — the pipelined path exposes no logits — 7.4
Part 8
- torch.cond / while_loop convert but run only on the bundled interpreter — no cpu/gpu/ane runtime support today — 8.1
- torch.cond/while_loop convert but the cpu/gpu/ane runtimes cannot run them — interpreter only, a device blocker — 8.2 🔇
Part 9
- Registry preset YAMLs exist only in the source tree — wheel installs SystemExit; clone coreai-models to read the recipes — 9.2
- AOT compiles only for Apple-Intelligence hardware: A17 Pro+, M1+ Macs, M2+ Vision Pro — one .aimodelc per arch — 9.3
Part 10
- GPU-pipelined Core AI lacks logits and forced continuation, so guided generation and MMLU-style scoring cannot run. — 10.README
- Registry compression presets reference YAMLs that exist only in the source tree; wheel installs exit with SystemExit. — 10.3
- An uncompiled .aimodel will not run on iOS at all; only the compiled .aimodelc loads there. — 10.3
Part 12
- rich and regex are imported at module level but undeclared; a bare pip install crashes at import. — 12.4
- macOS 26.2 is the hard gate for RDMA-over-Thunderbolt distributed inference; older machines simply can't join. — 12.5
- mlx_lm.lora imports two more packages at module scope that setup.py never declares; bare installs crash. — 12.6
Part 13
- @available alone is not enough — without the trait/linker gate the app fails at runtime on OSes that compiled fine — 13.1
- @available alone won't save you — the adapter's own header demands a runtime gate as well — 13.3
Part 14
Part 15
- compile exits 0 for any arch; codes track device ids, not names — green CI, invalidCompiledModel in users' hands — 15.README 🔇
- AOT compilation has a far narrower hardware floor than the framework — AOT assets exclude devices the framework supports — 15.1
- A green compile the device rejects — exit 0 proves nothing; the failure is invalidCompiledModel in the field — 15.1
- xcrun coreai-build compile exits 0 for architectures the device will reject — only a device load validates — 15.1 🔇
- A bad app-group entitlement silently drops to the per-bundle cache — specialization cost and storage double — 15.1
- Guided generation (@Generable) is not supported on GPU-pipelined engines — 15.1
- Grammar-constrained decoding needs logits; GPU-pipelined bundles never expose them — fastest backend loses @Generable — 15.1
- iPad RAM follows storage tier — 1–2 TB iPad Pros have more RAM; same-name smaller models jetsam your tested config — 15.2
Part 16
- AnalyzerInput's sample-buffer initializer is iOS 27.0+ — adopting it raises your OS floor — 16.1
- bufferDuration is iOS 27.0+ only — 16.1
- bufferFormat is iOS 27.0+ only — 16.1
- The priority/modelRetention/ignoresResourceLimits initializer is iOS 27.0+ — 16.1
- ignoresResourceLimits is iOS 27.0+ only — 16.1
- The .assistant domain's single intent is Japan-only — a region gate on the whole domain — 16.2
- @available says 26.4 but the cluster is absent from the 26.5 interface — treat the 27.0 SDK as the real floor — 16.2
- watchOS is absent from the tool's availability annotation — compiler-attested; plan no watch adoption — 16.4
Part 17
- Bring-your-own models lose @Generable on GPU-pipelined Core AI bundles; the fastest backend never exposes logits — 17.1
- BarcodeReaderTool lists watchOS but OCRTool does not; a watchOS target reaching for OCR finds nothing — 17.1
- Copying 2026 samples' reactive-only gating means users discover Apple Intelligence is unavailable only after tapping — 17.1 🔇
- No App Store required-device-capability exists for Apple Intelligence; incapable devices can always install your app — 17.1
- @Generable needs logits the GPU-pipelined Core AI engine never returns; the fastest backend cannot do guided generation — 17.2
- The GPU-pipelined engine samples on-GPU and returns no logits; @Generable fails at runtime, not at build time — 17.2 🔇
- Path table: @Generable works on FM and via MLXGuidedGeneration but not on GPU-pipelined Core AI bundles — 17.2
- TOC pointer: the load-time crash from an interface/dylib mismatch that no runtime guard can catch — 17.4
- The load-time failure no guard can catch: interface/dylib mismatch SIGSEGVs before main — 17.4
- The FM-27 beta interface declared a symbol the dylib lacked; respond() SIGSEGVed emitting usage until mlx fix #439 — 17.4 🔇
- Core AI Debugger requires a macOS 27 host and lists only iOS, iPadOS, and macOS paired devices — 17.5
- AOT compiles only for Apple Intelligence hardware (A17 Pro+, M1+); older devices silently specialize on device instead — 17.5
- CoreAI.framework is absent from the iOS Simulator SDK; every file importing CoreAI fails to compile for simulator — 17.6
- The beta .swiftinterface declared API the dylib lacked: code compiled fine and segfaulted at load, before main — 17.6
Performance cliffs¶
Silent slowdowns — CPU/GPU fallback, ANE ineligibility, cache misses, respecialization, sync stalls.
Part 1
- GPU runtimes shed 50-60% of throughput over 10 sustained minutes on iPhone 17 Pro; the ANE retains ~65-67%. — 1.1
- Without AOT + AIModelCache, cold specialization stalls launch: ~4.8 s at 0.8B, ~29 s at 2.3 GB, 194 s for one 3 GB… — 1.1
- Recurrent-state models (SSM/Mamba2) refuse KV rewind; the running scan cannot truncate, so every edit re-prefills. — 1.1
- trimKVCache(to:) returns negative on unsupported rewind, nothing throws — chats hit 23 s/turn on the wrong model. — 1.1 🔇
- Below-floor devices get no .aimodelc; on-device respecialization brings back the multi-second first-launch stall. — 1.2 🔇
- A deployment target under 26.2 defines MLX_METAL_NO_NAX and drops every NAX kernel; only a scrolled CMake warning says… — 1.2 🔇
- Background FM execution is OS-throttled with no priority control (thread 833666). — 1.2
Part 3
- Cache invalidation never throws — a reordering transform or time-interpolated instructions makes every turn O(N) again. — 3.README 🔇
- Contents entry: architectures that cannot prefix-cache. — 3.1
- A measured context overflow took 92.7 seconds; enforce an outer deadline as well as catching the typed error — 3.1
- Cache invalidation's only symptom is a longer prefill bar in Instruments — no error, no log line exists. — 3.1 🔇
- Model switching re-prefills the shared transcript on the new engine — 2.35 s switch-in measured; KV reuse is per-model. — 3.1
- Heading: the model-selection consequence — architectures that cannot prefix-cache. — 3.1
- A conditional above static instructions silently invalidates the cache — TTFT climbs turn over turn, no diagnostic. — 3.2 🔇
- trimKVCache returns -1 whenever SSM state exists — Qwen3.5, LFM2.5, Granite 4 re-prefill every turn, silently. — 3.3
- Linux streaming buffers the whole response and delivers one burst instead of incremental output — 3.3 🔇
- Hybrid and linear-attention models refuse the KV trim — every turn re-prefills; the efficiency pick makes chat slower. — 3.4
Part 4
- Linear-attention state cannot rewind for prefix reuse, so SSM models re-prefill the entire conversation each turn. — 4.README 🔇
- The OS specialises a shipped .aimodel per device before it runs — large models take long; keep it out of user flows. — 4.2
- Prefix KV reuse measured 101x on turn-2 TTFT — but hybrid/SSM models return -1 and silently re-prefill every turn. — 4.2
- Heading: linear attention forfeits prefix caching entirely. — 4.4
- Hybrid models refuse the trim (-1); the fallback re-prefills — turn-2 TTFT 20x worse and no API reports why. — 4.4 🔇
Part 5
Part 7
- Hello-world NDArray(shape:scalarType:) can mismatch the specialized layout: a silent layout copy on every inference — 7.README 🔇
- Holding states in a dictionary you also read leaves NDArray non-unique — COW copies the whole KV cache every decode… — 7.README 🔇
- Segmentation re-encodes unchanged images and lazy diffusion reloads components; malformed detector shapes look like a… — 7.README
- Summary with includingStatistics:true is considerably slower on large models — pass false for structure probes — 7.1
- AOT compilation does not remove on-device specialization; specialize() controls when it runs, not how much work it does — 7.1
- Probing the cache with .default then loading with .gpu options misses the cache: the key includes SpecializationOptions — 7.1
- CoreAISegmentationEngine re-runs image_encode on every segment() call — the 76% speedup needs caller-side feature… — 7.1
- The layout-conversion copy: a default-allocated tensor gets converted on every inference with no observable symptom — 7.1
- Contiguous row-major NDArray vs specialized layout: the framework copies your tensor every inference, forever, silently — 7.1 🔇
- Pre-allocating an output view forces a copy for constant-backed outputs the framework would otherwise return zero-copy — 7.1
- AsyncValue.ndArray returns a copy when the value wraps an MTLBuffer — the zero-copy path silently isn't — 7.1
- Reading .ndArray from an MTLBuffer-backed AsyncValue copies the data to avoid aliasing — use the MTLBuffer directly — 7.1
- expectFrequentReshapes on an all-static graph silently discards the AOT asset and recompiles on device — 7.2
- expectFrequentReshapes=true on a static graph drops AOT specialization — no log, just a slow (or jetsam-killed) load — 7.2 🔇
- Arbitrary prompt lengths re-specialize the graph — bucket prefill into a few fixed shapes compiled once — 7.3
- Incident-grade community finding: the reshape hint can destroy AOT benefits — see the fixed-shape measurement below — 7.3
- Community-measured: expectFrequentReshapes on a fixed-shape graph kills the AOT bundle — set it only on the dynamic path — 7.3
- Copy-on-write copies the entire KV cache every decode step when the state buffer isn't uniquely referenced — 7.3
- The frozen Noema snapshot parks placeholders so working state stays uniquely owned — no per-token COW copy. — 7.3
- Encode-once reuse requires caller-side caching — CoreAISegmentationEngine re-runs image_encode every call, no cache API — 7.3
- 'MLX 2x faster' measured a hand-rolled per-token loop — Apple's pipelined engine runs the same weights ~3.5x faster — 7.3
- Pipelined engine overshoots EOS into device KV — cross-turn reuse is impossible and TTFT is history/decodeRate — 7.3
- Historically, dropping a stream at EOS kept decoding to maxTokens and delayed the next turn; upstream fixed it — 7.3
- Models carrying recurrent extra states reject trimKVCache — hybrid/SSM architectures cannot prefix-reuse across turns — 7.3
- trimKVCache guards on extraStates.isEmpty — graphs with SSM/conv states return -1 and pay full re-prefill every turn — 7.3
- Intervals look fine but memcpy dominates the Time Profiler: the copy-on-write KV trap of §8.1 — 7.3
- swift run defaults to Debug, where -Onone per-element closures make resets take seconds — build release for any… — 7.4
- The structure probe swallows errors and defaults to .dynamic — an ANE-meant model silently gets GPU specialization — 7.4
- Prefix reuse needs byte-identical re-renders — unsorted tool-call dict keys collapse the LCP and silently re-prefill — 7.4
- A failed structure summary silently defaults to dynamic GPU specialization options before the loaded functions reveal… — 7.5
- ImageSegmenter re-runs image_encode for every prompt; same-image feature reuse requires an application-owned… — 7.5
- Lazy diffusion unloading saves residency but repeated requests reload every component and repay stage-load latency — 7.5
Part 8
- Default decompositions discard fused attention; conversion and numeric checks still succeed — 8.README 🔇
- Renaming a segmenter selects PreparedModel dynamic GPU preference instead of its Neural Engine preference — 8.README 🔇
- torch.export's default decomposition table splits SDPA into matmul+softmax — you silently lose the fused kernel — 8.1
- No error marks a lost composite — count ops with freqop or assert composite.scaled_dot_product_attention in the IR — 8.1 🔇
- Externalizing a bare class preserves a boundary without providing an optimized composite kernel — 8.1
- Entrypoint names are routing: nonstandard names make the loader classify .dynamic and request GPU instead of ANE — 8.1
- The 76% faster second inference requires caller-side caching Apple's own package does not implement — 8.1
- CoreAISegmentationEngine re-runs image_encode every segment() and exposes no way to hold backbone features — 8.1
- instance_norm becomes a composite only when use_input_stats is truthy — otherwise you quietly lose the optimized kernel — 8.2 🔇
- The function containing a custom kernel is GPU-resident — splitting entrypoints pins that function off the ANE — 8.3
- A custom kernel is a fusion barrier — the surrounding graph slows in ways your kernel's own timing never shows — 8.3
- Kernel edges materialize in the dtype the kernel asks for — boundary casts become real ops that inflate the graph — 8.3 🔇
Part 9
- enable_per_channel_scale=True lowers to rank-6 LUTs the ANE (max rank 5) rejects — the model silently moves to GPU — 9.README 🔇
- Compute-unit fallback is documented and silent — correct outputs, several times slower, visible only in tooling — 9.README 🔇
- The ANE rank-5 ceiling: rank-6 tensors force the op — and its fused neighbors — off the Neural Engine — 9.2
- enable_per_channel_scale improves PyTorch numerics slightly and silently moves the model to GPU — invisible on a Mac — 9.2 🔇
- The 76% figure needs backbone-feature caching CoreAISegmentationEngine doesn't do — it re-runs image_encode every call — 9.2
- The 76%-faster second inference requires caller-side caching Apple's package does not do — 9.2
- Cheat sheet: enable_per_channel_scale=True means rank-6 LUT, ANE rejection, and silent GPU fallback — 9.2
- Complex dtypes exist in MLX but are excluded from NAX — complex matmuls run on the older, slower kernels — 9.3
- A bare Python float literal can move an op — and its fused pattern — off the ANE to the GPU — 9.3
- A literal fp16 can't represent materializes as an fp32 constant — the consuming op leaves the ANE with no warning — 9.3 🔇
- Recognized entrypoint names select the sample loader's ANE preference — rename them and you get the GPU policy — 9.3
- CoreAISegmentationEngine re-runs image_encode on every call and exposes no cache — the headline speedup needs your code — 9.3
- A deployment target below 26.2 silently drops every NAX kernel — the only trace is a CMake configure-time warning — 9.3
- Failure #2: per-channel-scale palettes lower to rank-6 LUTs — the whole op silently moves to GPU — 9.3
- Failure #3: an fp32 operand makes the node fp32 and ANE-ineligible — check Compute types in the model viewer — 9.3
- Failure #4: an epsilon fp16 can't represent (1e-6) fails the round-trip predicate — same silent ANE exit — 9.3
- Failure #5: F.silu lowers to cast+swish(f32)+cast — three ANE-invalid ops from one call — 9.3
- Failure #6: one dynamic dimension breaks the ANE's fully-static-shape requirement — silently ineligible — 9.3
- Failure #7: FP8/FP4 weights have no ANE compute path — execution lands on GPU or CPU — 9.3
- Failure #11: MLX built below target 26.2 drops all NAX kernels — semi-silent, one configure-time warning — 9.3
- Failure #18: coreai_kit.run defaults to cpu_only — benchmarks copying those defaults silently measure the CPU — 9.3
- includingStatistics:true is considerably slower on large models — false returns versions and signatures, enough to probe — 9.3
Part 10
- ANE-authored model quietly runs on GPU: the coreai-models loader infers compute unit from entrypoint names. — 10.README 🔇
- Per-channel LUT scaling creates rank-6 tensors the ANE rejects, silently moving inference to the GPU. — 10.README 🔇
- enable_per_channel_scale=True makes rank-6 tensors that silently push the model off the ANE; it runs and burns battery. — 10.1 🔇
- A surviving nn.Linear converts fine but becomes a segmentation point, splitting the graph off the Neural Engine. — 10.1 🔇
- Odd mask dtype/shape or GQA combo makes PyTorch's dispatcher pick the math backend; the fused SDPA quietly decomposes. — 10.1 🔇
- Name entrypoints encode_image/encode_text/predict and the loader classifies your ANE model .dynamic, requesting the GPU. — 10.1 🔇
- CoreAISegmentationEngine re-runs image_encode on every call; the session's 76% caching win needs your own orchestration. — 10.1 🔇
- trimKVCache returns -1 whenever extraStates is non-empty, so SSM and hybrid models silently re-prefill every turn. — 10.2
- Changing SpecializationOptions makes a second cache entry, doubling storage and cost; any OS update flushes the cache. — 10.2
- nn.functional.silu lowers to cast+swish+cast the ANE cannot run; the graph partitions onto GPU/CPU with no diagnostic. — 10.3
- enable_per_channel_scale=True can push the model off the Neural Engine, per Apple's own shipped config comment. — 10.3
- Historical large-graph optimization hangs require a 0.4.3 upgrade; current hangs must be minimized and reported — 10.3
- swift run builds Debug by default; benchmark from a Release build or your numbers measure the wrong thing. — 10.3
Part 11
- A macOS deployment target below 26.2 makes MLX drop every accelerated kernel behind only a CMake warning. — 11.README 🔇
- Default macOS builds target below 26.2, so MLX drops all NAX kernels with just a CMake warning (PRs #3622, #3824). — 11.2 🔇
Part 12
- Fused attention can fall back to matmul-softmax-matmul, preserving results while materializing large score tensors. — 12.README 🔇
- Evaluating loss and gradients separately runs the graph twice per step; batch both into one mx.eval. — 12.1
- A varying Python scalar argument recompiles a compiled function on every call; it presents as compile being slower. — 12.1
- int/float/str/None args are baked into the compile cache key; a varying scalar silently recompiles every call. — 12.1 🔇
- shapeless=True only exempts shape changes; scalar constants varying across calls still create distinct cache entries. — 12.1
- The default-stream context manager is part of the compile cache key; calling under another device recompiles. — 12.1
- Per-call stream setup costs a uniform 55-77 ms TTFT regression (mlx-lm#1435); hoist it out of the hot path. — 12.1
- mx.save forces evaluation of the pending graph; a checkpoint line can trigger the entire deferred computation. — 12.1
- TOC: the silent SDPA fallback from fused kernel to unfused matmul-softmax. — 12.2
- complex64 matmul is gated out of the NAX path on Metal, while CUDA gives complex TF32 fast math instead. — 12.2
- A source build targeting below macOS 26.2 defines MLX_METAL_NO_NAX: a working MLX that is simply never fast on M5. — 12.2 🔇
- Apple's trace shows simdgroup_matrix kernels leave M5 matrix hardware idle; the same matmul is ~7x faster on TensorOps. — 12.2
- mx.fast SDPA silently takes the unfused path for many configurations; right answer, worse speed and memory. — 12.2
- SDPA fallback computes correct output unfused, materialising the full score tensor; throughput and memory betray it. — 12.2 🔇
- Miss a NAX dispatch gate and you get correct numbers from a much slower kernel, with nothing logged. — 12.3
- Shapes failing the K%64/transpose check dispatch a non-NAX kernel: no warning, same numbers, very different M5 speed. — 12.3 🔇
- --draft-model silently disables continuous batching; concurrent requests serialize. — 12.4
- An unregistered drafter makes the Swift MTP iterator fall back to single-token decoding: no error, zero speedup. — 12.4
- A draft model or a seed silently turns the concurrent server sequential; concurrency holds only when batchable. — 12.4
- A draft model or a fixed seed silently disables continuous batching; the server serves sequentially. — 12.5
- Cache classes that aren't trimmable forfeit prompt-prefix reuse entirely; every turn pays a full prefill. — 12.5
- Distributed runs need MLX_METAL_FAST_SYNCH=1; without it, CPU-driven communication pays slow GPU-CPU synchronisation. — 12.5
- DoRA dequantises the full base weight twice per forward, materialising dense layer-size matrices; QLoRA savings vanish. — 12.6
- Comparison table: DoRA runs on a quantized base but dequantises every step; don't use it where QLoRA memory matters. — 12.6
- The length sort keys on len() of the raw record dict, a constant: batches mix short and long rows, causing random OOMs. — 12.6
- JACCL recv spins forever on peer loss and the ring socket thread dies silently, wedging all ranks (#3910, #3862, #3830). — 12.6
Part 13
- MTP drafters need manual registration; without it decoding silently falls back to single-token — no speedup, no error — 13.2
- Prefill runs inside the cache initializer — constructing it is the expensive step, not a cheap allocation — 13.2
- Hybrid and linear-attention models have no prefix caching — every RAG query re-prefills; 0.2 s vs 20 s to first token — 13.2
- A prewarm witness that doesn't match exactly never binds — prewarm silently no-ops, first-token latency stays high — 13.3
- Rejected fast-forward tokens silently fall back to masked sampling — correct but slower; only the counter shows it — 13.3
- Each helper call scans the full vocabulary (three passes on a 150k vocab) — cache biases and GrammarTokenizer — 13.3
Part 14
- expectFrequentReshapes requests a reshape-tolerant specialization — on a static graph it costs the fast path — 14.1
- Thermals move numbers 2.3–4.1× — a day of device use silently degrades a 25 ms op; benchmark cold and hot — 14.1
- A community helper defaults to cpu_only() — copied code silently runs ~9–10× slower; it's the parity option — 14.1
Part 15
- The same export recipe can run 2.2 times slower with twice the memory when built on a different macOS host. — 15.README 🔇
- expectFrequentReshapes=true on a fixed-shape graph abandons the AOT specialization — device-validated, can SIGSEGV — 15.1
- Code comment: set expectFrequentReshapes explicitly false on static graphs — asking was measured to kill AOT and SIGSEGV — 15.1
- Your build machine is a benchmark variable — the same export can be 2.2× slower and 2× heavier with zero diagnostics — 15.2 🔇
Part 16
- A [Entity] parameter fully resolves every element before perform() — hidden N-query stall; EntityCollection passes ids — 16.2
- Code comment: the naive displayRepresentations is correct but slow enough to break awareness — 16.3
- The naive implementation compiles and is correct — and stalls long enough to break the feature — 16.3
- A naive displayRepresentations turns awareness into a stall — it is called for every entity — 16.3
Part 17
- CoreAISegmentationEngine re-runs image_encode on every call; the 76% second-inference saving needs your own cache — 17.2
- Refusal.explanation re-runs the model for seconds; awaiting it near the main actor freezes the UI with no crash report — 17.3 🔇
- An optional sample-loader pattern can request an unintended compute unit; inference silently runs on the wrong backend — 17.5
- Apple's own CoreAISegmentationEngine re-runs image_encode per call; the 76% saving requires a cache you must write — 17.5
- Hybrid linear states cannot rewind to a cached prefix, so reuse falls back to a full prefill — 17.5
- The segmentation engine re-runs image encoding on every call unless the caller caches features — 17.5
- AOT assets still require device specialization; the community example reported a 194-second wait — 17.5
- Specialization replaces .mlmodelc compilation and its cache entry is invalidated on every OS update — 17.5
- The stale-host 2.2x slowdown hides on large bandwidth-bound models; only small-model benchmarks reveal it — 17.6
Resource growth¶
Silent memory or disk growth, leaks, quota consumption.
Part 2
Part 4
- Heading: reasoning spends your context, invisibly. — 4.1
- Reasoning tokens fill the 32K window while appearing in nothing you render — overflow errors from chats that 'fit'. — 4.1 🔇
- No checkCancellation exists in Apple's executor — a local engine keeps generating after the consumer cancels. — 4.3
Part 5
- TOC: memory across the Python/Swift boundary — fd leaks after ~240 image calls, retained attachments, double-free… — 5.2
- Native memory and fds cross the Python/Swift boundary — batches leak unless sessions are recreated and releases run. — 5.2
- pip's apple-fm-sdk 0.2.1 still has the image fd leak; the fix landed 2026-07-07 on git main only — install from main. — 5.2
Part 7
- Near-identical SpecializationOptions values each get their own multi-GB cache entry and three-minute stall — 7.README 🔇
- Each concurrent run() allocates its own intermediate buffers on demand — parallelism silently multiplies scratch memory — 7.1
- Every in-flight run() gets its own auto-allocated intermediate buffers — scratch memory grows with no API to bound it — 7.1 🔇
- SpecializationOptions is part of the cache key — every distinct value mints a new multi-GB cache entry — 7.1
- Two slightly different options values: two cache entries, two specializations, two multi-GB copies on disk — 7.2
- A mutable SpecializationOptions property drifting between code paths silently duplicates multi-GB cache entries — 7.2 🔇
- Prewarming a host-cache graph would allocate the full static KV cache — gigabytes; prewarm the shape, not the capacity — 7.2
- .fixedSize KV allocates maxContextLength up front — multi-GB on long-context models, and every step gets slower — 7.4
Part 9
- group_size=1 means one LUT per output channel — the LUT overhead is why Apple's presets use 8/16/32 — 9.2
Part 10
- AOT is no memory cure: a 1.8 GB ANE monolith loads on iPhone 17 Pro, then the first inference step is jetsam-killed. — 10.3
- .fixedSize pre-allocates the KV cache at full maxContextLength; short sessions pay the whole context's memory. — 10.3
Part 12
- mlx_lm.load's default lazy=False evaluates every parameter at load - an 18.2 GB spike on a 35B MoE before any token. — 12.1
- A loop that never calls mx.eval builds an ever-growing lazy graph; memory climbs until evaluation or OOM. — 12.1
- Community-measured functional-cache leak: memory grows across steps until the cache is explicitly cleared. — 12.1
Part 13
- iOS jetsam gives no signal: no throw, no memory-warning callback, no deinit — the app just closes on the user — 13.README 🔇
- Jetsam arrives with no throw, no reliable memory warning, no deinit — 'Terminated due to memory issue' is all you get — 13.1
- Fused SDPA is head-dim-gated; unsupported dims silently materialise an L² score tensor — inexplicable prefill memory — 13.1
Part 15
- A successful load is not a fit test — first inference adds activations and KV, and compute unit moves headroom 2× — 15.README 🔇
- Prewarming a graph with static-shape host KV I/O allocates the whole cache up front — a net loss; gate your prewarm — 15.1
- SpecializationOptions is part of the cache key — two variants mean two multi-gigabyte specializations — 15.1
- Slightly different SpecializationOptions from two code paths silently double the multi-GB cache and re-stall first load — 15.1 🔇
- Extension memory limits count Core AI models — a model fine in the app can jetsam its extension — 15.1
- .persistent turns off source-deletion reclamation — deleted sources strand multi-GB orphans until the next OS update — 15.1
- TOC: load OK, run dead — a model that loads can still die on its first inference step — 15.2
- Loading establishes weights only; the first step adds activations, workspace, maybe a full-context KV cache — 15.2 🔇
- mmap'd weights look free until touched — residency grows to full size on unified memory; headroom checks lie — 15.2 🔇
- Measured ceiling: an 18 GB int4 35B gets signal 9 on a 12 GB iPhone 17 Pro — ~5–6 GB is the phone-class limit — 15.2
- The same 1.8 GB core leaves ~2.8 GB headroom via ANE but ~6.0 GB via GPU — no API reports the difference — 15.2 🔇
- Forum 824753 (community, status unknown): ~40 GiB of 'other' allocations — watch for runaway growth — 15.2
Part 17
- Each adapter-related call leaks about 100 MB of orphaned APFS clones that ordinary disk tools never surface — 17.2
- Two differing SpecializationOptions create two multi-gigabyte cache entries for one model, silently doubling disk — 17.5
- Loading with non-identical options specializes twice: two cache entries, two copies on disk, no warning — 17.5
- SpecializationOptions is part of the model cache key; varying it multiplies multi-gigabyte cache entries — 17.5
Precision loss¶
Silent numeric precision or dtype changes — TF32, quantization side-effects, accumulation regimes.
Part 9
- --n-bits and --group-size override BOTH encoders — passing 4 silently drags the text encoder down from w6/gs8 — 9.1
- export.py --n-bits applies to both encoders — 4 silently drags the text encoder from its 6-bit/gs8 default — 9.2
- fp32 matmuls on MLX's NAX path silently run at TF32 relaxed precision unless MLX_ENABLE_TF32 disables it — 9.3
- 64-bit types are narrowed on the way in: int64 to int32 and fp64 to fp32, silently — 9.3
- The converter narrows int64/fp64 to 32-bit silently — NDArray has 64-bit ScalarTypes the converter never produces — 9.3
- MLX's own caveat: mxfp8 results differ on <1% of elements and can exceed 1 ULP for small values; nvfp4 matches exactly — 9.3
- MLX float32 matmuls silently run at TF32 on the NAX path — the warn-once PR (#3883) was closed unmerged, so nothing… — 9.3
- Failure #12: MLX fp32 matmul at default env runs TF32 relaxed precision — set MLX_ENABLE_TF32=0 and diff — 9.3
- Failure #15: int64 index tensors are narrowed to int32 — values above INT32_MAX overflow, mostly unclamped — 9.3
Part 12
- M5 float32 matmul silently runs at TF32-class precision (2^-10.4 vs 2^-19.8 error); set MLX_ENABLE_TF32=0 before import. — 12.README 🔇
- mx.load's format list omits gguf, and unsupported GGUF quantization formats silently cast tensors to another dtype. — 12.1
- TOC: precision you did not choose - float32 matmuls at TF32 class with no runtime signal. — 12.2
- np.array on bfloat16 raises a cryptic PEP 3118 error, and NumPy float64 silently narrows to MLX float32. — 12.2
- On M5 + macOS 26.2+, float32 matmul defaults to reduced internal precision with no runtime signal. — 12.2
- M5 float32 matmul returns plausible values ~3 orders of magnitude less accurate; x.dtype still says float32. — 12.2 🔇
- Quantized-KV settings change output quality through three separate mechanisms, with no signal. — 12.4
Part 13
Part 17
Misleading signals¶
Errors, logs or metrics that name the wrong cause; swallowed errors; observation APIs that emit nothing.
Part 1
- The common catch pattern omits SystemLanguageModel.Error, hiding actionable unavailability in a generic catch. — 1.README 🔇
- All seven Core AI benchmark rows used the no-@Generable pipelined engine — for guided generation the config is… — 1.1
- The 2.47x claim rests on a stale macOS 26 export (~500 tok/s re-exported) and a Debug-build MLX baseline on iPhone. — 1.1
- The source conflicts about int8 versus 4-bit weights; its table is not a controlled numerics comparison — 1.1
- isAvailable == true is not a promise that a request will succeed — treat availability as advisory only. — 1.2
- isAvailable == true yet requests fail with error -1 wrapping undocumented ModelManagerError 1046, even on real devices. — 1.2 🔇
- The Simulator on a macOS 27 host runs the host's model, not your target's; adapters are broken outright (issue… — 1.2
- The Simulator on a macOS 26 host emits meaningless -1 errors — pure host/SDK version skew (thread 831404). — 1.2
- The Shortcuts 'Use Model' action works but errors cannot be detected — failures pass silently (thread 813757). — 1.2
- A preflight verdict of .onDeviceOnly/.cloudOnly is no success guarantee; wrap each respond in the three-arm catch. — 1.2 🔇
Part 2
- String-mode refusals return as successful Strings, not errors, and poison the transcript for later turns. — 2.README 🔇
- Assigning transcript.history mid-response compiles clean; the failure erupts as an error from an unrelated await. — 2.1 🔇
- Propagate .emptyTypeChoicesSchema — it catches unloaded .anyOf arrays; Apple's Skills writes try! there, which traps. — 2.2
- Refactor into a file importing only FoundationModels and the break reads like a missing SDK, not a missing import. — 2.4 🔇
- spotlight_search never throws on malformed arguments; a code-100 JSON error rides inside the Prompt output, invisible… — 2.4
- contextSizeExceeded throws but never says what filled the window — tool result payloads are the invisible culprit. — 2.4 🔇
- A reactive-only design missing the SystemLanguageModel.Error arm mishandles availability failures silently. — 2.6
- Availability failures are SystemLanguageModel.Error, not LanguageModelError — ladders on the latter miss them. — 2.6
- Table: in string mode a model-level refusal does not throw — it returns a refusal string as a successful response. — 2.6
- Heading: the refusal that is just a String. — 2.6
- Decision table: a 'Sorry, I can't…' String is a silent string-mode refusal — switch to Generable so it throws. — 2.6
- Symptom table: a polite refusal string with no error is a string-mode refusal — use guided generation to make it throw. — 2.6
Part 4
- Heading: availability is not a health check. — 4.1
- availability == .available says nothing about quota — the most common real failure is invisible to every check. — 4.1 🔇
- PCC in the Simulator throws a content-free error that reads as your bug — a known issue per Apple engineering. — 4.1
- This executor never throws rateLimited/contextSizeExceeded/timeout — a 429 arrives as generic httpError with raw bytes. — 4.2
- The cited beta adapter omits usage to avoid a missing symbol; verify stable behavior before token accounting. — 4.2
- A backend is not obliged to use the typed error vocabulary — and Apple's own executor mostly doesn't. — 4.2
- Comparison table: MLX may report token usage absent or zero — the deliberate omission documented in §3.9. — 4.2
- Heading: Apple's own executor throws none of the typed LanguageModelError cases. — 4.3
- ChatCompletionsLanguageModel maps nearly everything to RequestError — typed rateLimited/timeout arms never fire. — 4.3
Part 5
- Simulator inference runs on the host Mac; an Xcode 27 SDK on macOS 26 manufactures error -1 that looks like your bug. — 5.README 🔇
- Simulator inference runs on the host Mac's OS; version-skew errors surface as a bare -1 that reads as your bug. — 5.1 🔇
- One availability branch is contaminated by a confirmed Apple bug — do not design around it. — 5.1
- availability returns .appleIntelligenceNotEnabled unless Siri is enabled, even with AI on — Apple-confirmed bug. — 5.1
- capabilities claims vision and tool calling on the 27.0 sim where both fail at runtime; it is a declaration, not a… — 5.1
- apple_fm_sdk.version is hardcoded 0.1.0 on a 0.2.1 package; capability checks keyed on it test a constant. — 5.2
- pytest outside the repo root fails on FileNotFoundError for fixtures — it reads like a broken install and is not. — 5.2
- Exceptions raised inside a tool's call() never reach your except block — they are stringified and fed to the model. — 5.2
- A tool exception becomes 'Tool error: ...' handed to the model; respond() succeeds and the caller never sees it. — 5.2 🔇
Part 6
- Positional judge/expert joins can misalign scores and report low kappa, falsely suggesting a badly calibrated judge. — 6.README 🔇
- An eval whose model config differs from the app's (guardrails, options) scores a system you don't ship, and stays green. — 6.1 🔇
- (3...8).contains reads 100% for a constant 8 — @Guide(.count(3...8)) fixed the range and collapsed the distribution… — 6.1 🔇
- Omit ModelJudgePrompt and the judge falls back to defaultInstructions — stable, plausible scores with zero app context. — 6.2 🔇
- Judge drift never throws and grows with your dataset; the only detector is the kappa calibration you must build… — 6.2 🔇
- Calibration contamination raises kappa — the judge looks better the more you break it, then ships behind a green test. — 6.2 🔇
- cohensKappa ?? 0 reports undefined kappa (single category, mismatched arrays) as chance-level agreement — wrong… — 6.2
- A judge returning 4 every time posts a perfect mean and zero sigma; aggregate only the mean and you ship it. — 6.2
- An eval on default guardrails while the app runs permissive ones scores a different system, and no test will say so. — 6.2
- TOC: the validator sees one sample at a time — cross-sample rules become always-true no-ops. — 6.3
- The validator runs on single samples; dataset-wide rules cannot be expressed and quietly validate nothing. — 6.3
- Cross-sample rules in a one-sample validator ('reviews must vary') are trivially true — check-shaped no-ops that pass… — 6.3 🔇
Part 7
- Compression metadata records the request; a caught quantization failure can ship float16 weights under a 4-bit label. — 7.README 🔇
- Adding .aimodel files without the Metal Toolchain fails the build with a Metal-compiler error that never names Core AI — 7.1
- A failed AOT load surfaces as 'CoreAIDelegates.AIModelError error 3', re-mapped downstream — the raw code names no cause — 7.1
- Instruments and the debug gauge swap the Load/Specialization colours — colour intuition from one misreads the other — 7.2
- The gauge's Open-in-Debugger/Export options don't work for events recorded before its report was open — open it first — 7.2
- ANECCompile() FAILED in the console during specialization is not necessarily an error — don't kill the run on first… — 7.2
- A successful compile proves nothing about the architecture — the device is the only validator — 7.2
- A historical AOT compile succeeded for an incompatible device architecture; validate on target hardware — 7.2 🔇
- std::bad_alloc from a Core AI load on iOS is almost always jetsam — check Console.app and the memory entitlement first — 7.2
- Metal Toolchain missing: model builds fail with a Metal-compiler error that doesn't point at Core AI — 7.2
- The number-one first-contact failure: the missing-toolchain build error blames Metal, and fresh CI runners lack it too — 7.2
- Without export-time debug metadata the Source Viewer shows no mapping to your Python — set the env vars before… — 7.3
- CoreAILanguageModel.init never calls verify() — a missing asset surfaces later as a raw Core AI error, not missingAsset — 7.4
- metadata.json's compression field records the requested compression, not what was actually applied to the weights — 7.4
- Bundle-format table: compression is the request (§2.11) — nothing validates it against the shipped weights — 7.4
- capabilities reports guidedGeneration optimistically before the engine loads — the claim can be false until first use — 7.4 🔇
Part 8
- Malformed MSL can survive export and load, then fail at load_function without compiler diagnostics or source location. — 8.README 🔇
- inspect succeeding is not evidence the asset will compile or load on-device (see the version gate) — 8.1
- Without ENABLE_DEBUG_INFO=1, debug metadata may be missing even when conversion and inference succeed — 8.1 🔇
- Validation is ATen-only: custom torch.library ops pass silently, then to_coreai() fails with a different error — 8.2
- Externalized bodies are decomposed with a table you didn't choose — clean validation, then a confusing unsupported-op… — 8.2
- Set USE_LOCAL_COREAI and ENABLE_DEBUG_INFO before conversion or profiles simply lack module/source attribution — 8.3
- Without HAVE_TENSOR the whole MPP header expands to nothing — just a 'no member named matmul2d' error far downstream — 8.3 🔇
- A bad kernel body is not a conversion error — it fails only at function bind, without any compiler diagnostic — 8.3
- Malformed MSL converts, saves and loads cleanly — the bind-time failure message contains no compiler diagnostic — 8.3 🔇
Part 9
- Undefined HAVE_TENSOR empties the whole header — the only symptom is a distant 'no member named matmul2d' — 9.3
- The debug gauge needs a direct CoreAI.framework link — reach Core AI through a package and the gauge never appears — 9.3
Part 10
- Debug gauge appears only with direct CoreAI linking; via a package there is no row, reading as if the model never ran. — 10.README 🔇
- Load and Specialization colors swap between the Debug gauge and Instruments; the same color means different work. — 10.README 🔇
- Green sync-point metrics can miss a decoder token divergence; validate a greedy token-exact generation loop. — 10.README 🔇
- A package that links CoreAI links it for itself; your app shows no Debug gauge row and no warning explains the absence. — 10.2 🔇
- More-menu hand-off items only cover events recorded after the report page opened; earlier repros silently lack them. — 10.2 🔇
- Load and Specialization colours swap between Debug gauge and Core AI instrument, so colour intuition misreads traces. — 10.2 🔇
- A RELEASE-converted asset opens as a seemingly working Debugger session; the Source Viewer is just absent, unexplained. — 10.2 🔇
- Similarity metrics are per-forward-pass; they cannot certify a decoding loop. — 10.2
- An all-green sync-point board can coexist with different generated text: per-step errors compound in the decode loop. — 10.2 🔇
- Inside the 0.4.0 incident: tooling reads the broken asset fine, making it look recoverable when it is not. — 10.2
- coreai-build inspect parses a 0.4.0-dead asset perfectly; every recovery attempt fails, each costing someone a day. — 10.2 🔇
- Historical broken exports omit producer metadata; audit the source aimodel to identify the failing export release. — 10.2
- The aimodelc producer identifies coreai-build; use the source aimodel producer to identify the converter. — 10.2
- Without two env vars set at export, the Debugger's navigator has no debug metadata to show. — 10.3
- inspect still reads the 0.4.0-dead asset fine, which makes it look recoverable; it is not. — 10.3
- 'Won't open' hides two gates: the runtime load gate is OS-side, the authoring parse gate is in the wheel. — 10.3
- coreai-build compile exits 0 for any requested architecture; only a device load validates the choice. — 10.3
- A compile that exits 0 and an asset that loads on device are different claims; validate by loading. — 10.3
- Embedding an aimodel directory makes the installer reject it as an invalid nested bundle; download it instead. — 10.3
- A Resources folder at the iOS bundle root triggers a misleading embedded.mobileprovision code-signing failure. — 10.3
- The 'growing strategy' error tells you to re-export with --dynamic-sized-kvcache-gpu, a flag no shipped CLI has. — 10.3
Part 12
- The server returns HTTP 404 for model-load, OOM and tokenizer failures, and tools to a non-tool model only warns. — 12.README 🔇
- Lazy evaluation moves exceptions to whatever line forces evaluation, far from the op that caused them. — 12.1
- A failing op raises nothing when recorded; the exception fires at a later print or eval, often inside a library. — 12.1 🔇
- The first compiled call pays graph build, codegen and Metal compilation; un-warmed benchmarks measure the compiler. — 12.1
- gpt-oss attention sinks plus a quantized KV cache kill the generation thread; the client sees only a timeout. — 12.2
- mx.get_peak_memory excludes the buffer pool; one M5 Max run reported 46 GB while the OS saw ~110 GB. — 12.2
- --kv-bits starts cleanly, /health answers 200, then the first request crashes on sliding-window models (mlx-lm#1573). — 12.4 🔇
- Quantized KV with gpt-oss kills the generation thread; the request never returns and presents as a network timeout. — 12.4 🔇
- /health is a static handler; it answers 200 regardless of whether the model loaded or the generation thread is alive. — 12.5
- Model-load, OOM and tokenizer failures return HTTP 404 - the mistyped-URL status; the real error hides in the body. — 12.5
- DoRAEmbedding's guard tests QuantizedLinear, not QuantizedEmbedding; the meant error never fires, an unrelated one does. — 12.6
- get_total_parameters unpacks quantized weights in the denominator; the printed trainable fraction is misleadingly small. — 12.6
- The trainer's printed peak memory excludes the buffer pool; the real footprint is active plus cache memory. — 12.6
- val_info['iteration'] is it-1 while train_info uses it; naive metric joins misalign validation by one step. — 12.6
- The before/after perplexity comparison lies three ways; perplexity on a tuned distribution always improves. — 12.6
Part 13
- Split tokenizer repos get a no-op progress handler: the bar hits 100% while a second unreported download runs — 13.1
- Macro expansion references six modules at your call site — missing imports error inside code you never wrote — 13.1
- Linking only MLXLMCommon empties the registry; the free loader shows the VLM error, hiding the real LLM failure — 13.1
- Memory.snapshot() reports MLX's allocator only, not process footprint — it cannot warn you about jetsam — 13.1
- #hubDownloader macros expand to symbols at your call site — missing imports produce baffling errors in generated code — 13.2
- The VLM factory runs first and intermediate errors are swallowed — the message you see may be the wrong factory's — 13.2
- A missing import at the macro call site errors inside the expansion — the message never names the import fix — 13.3
- noModelFactoryAvailable surfaces mid-download when MLXLLM isn't imported — the error site hides the linking cause — 13.3
- .available does not mean the weights are complete — a partial download still reports available — 13.3
- Usage is never forwarded to the framework — Foundation Models usage metrics stay empty on the MLX path — 13.3
- flushLogs() always returns nil — the log-retrieval API hands back nothing, ever — 13.3
Part 14
- TOC: asset-generation coverage is not numerical parity — a bundle that generates is not one that computes correctly — 14.1
- Conversion succeeds while silently listing unresolved tensors in metadata['unresolved_extra_inputs'] — read it every… — 14.1
- Generated assets are not numerical parity — tolerances compare against MLX's own capture, never a Core AI execution — 14.1
- match_by_order=True pairs outputs positionally — a shifted output order gives a green comparison of the wrong tensors — 14.1
- --runtime-backend auto silently picks Swift on Darwin unless a Python-only flag flips it — runs measure different… — 14.1
- Every Core AI test in the repo passes without running — green because skipped, not because it works — 14.1
- Code comment: check metadata['unresolved_extra_inputs'] after every conversion — success ≠ all inputs resolved — 14.1
Part 15
- Specialization reports no progress — minutes of silence that read as a hang — 15.1
- The specialization gauge appears only when you directly link CoreAI.framework — transitive linkage shows nothing — 15.1
- Code comment: the storage figure counts source assets only — specialized copies in the cache are invisible to it — 15.1
- iOS 27 betas report appleIntelligenceNotEnabled unless Siri is on — Apple-confirmed bug; don't require Siri in UX — 15.1
- Memory-pressure trim freed an in-flight MTLBuffer (mlx#3689) — surfaces as a GPU InvalidResource error, hiding the cause — 15.2 🔇
- Foundation Models exposes no tokenizer — every published tok/s figure for Apple's model is an estimate — 15.2
- Third-party tok/s for Apple's model carries ~±20% error — no tokenizer to count with, and nothing marks the estimates — 15.2 🔇
Part 16
- Unmapped errors leak raw domain strings to users through Siri — map them via AppIntentError and friends — 16.2
- Raw internal error domains reach users through Siri — unmapped errors are surfaced verbatim — 16.3
- SystemLanguageModel .available isn't sufficient — model-catalog failure can break the tool before your code runs — 16.4
Part 17
- SpotlightSearchTool's description contradicts its schema, so models fail to invoke it; Code=5000 fires while available — 17.1
- buildURLRequest keys versioning on a literal 'v1' path test; providers not on /v1 get mangled URLs and HTTP errors — 17.1
- The undocumented LanguageModelError -1 also occurs on physical devices; it is not a simulator-only artifact — 17.1
- Python tool exceptions never raise; they are stringified back to the model, so tool bugs look like model quality issues — 17.1
- compatibleAdapterNotFound really means the adapter is not downloaded yet; the name sends you auditing compatibility — 17.2 🔇
- A download that never starts yields an AsyncSequence with zero elements; 0% progress is indistinguishable from pending — 17.2 🔇
- A generic catch turns every user cancellation into an error banner; it reads as flakiness, not a ladder bug — 17.3 🔇
- An unsupported-locale prompt can silently succeed on the simulator; a catch arm never fires. — 17.3
- The same unsupported locale bridges differently by destination: simulator success, physical-device guardrailViolation… — 17.3
- Server 429s arrive as RequestError.httpError, never .rateLimited; backoff keyed on .rateLimited never fires — 17.3 🔇
- availability/isAvailable can report healthy while the call still throws (catalog asset and PCC entitlement failures) — 17.3 🔇
- A green Xcode 26 run proves MLX inference only; the FM adapter is not in that binary, so one check covers half — 17.4
- On 27 betas availability returns appleIntelligenceNotEnabled unless a Siri toggle is on; Apple confirmed it is a bug — 17.4
- Diffusion quantization failures warn while export continues; a completed export does not prove compression — 17.5
- The Core AI gauge and Instruments swap Load and Specialization colors; do not carry color intuition across tools — 17.5
- The Core AI Xcode gauge appears only with direct CoreAI.framework linkage; transitive linkage shows no gauge at all — 17.5
- TOC pointer: coreai-build inspect succeeds on assets the runtime rejects, making them look healthy — 17.6
- Why the asset break is vicious: inspect still reads the broken asset perfectly and nothing warns — 17.6
- inspect prints signatures, weights and dtypes from an asset the runtime aborts on; it looks recoverable and is not — 17.6 🔇
- A missing per-arch .aimodelc surfaces as ENOENT 'no such file or directory', sending you to debug file paths — 17.6
- coreai-build compile exits 0 for any architecture; only an on-device load reveals a wrong-arch artifact — 17.6
- A green compile validates nothing about the arch choice; a mis-targeted .aimodelc passes CI and fails on device load — 17.6 🔇
- Int4 quantization failures are swallowed by a try/except while the bundle manifest still claims quantization succeeded — 17.6
- compiler.py swallows quantize_weights failures and ships unquantized weights while metadata claims int4 success — 17.6 🔇
Version drift¶
The same code or artifact behaves differently across OS/SDK/tool versions with no signal.
Part 1
- On the 26 SDK MLXFoundationModels builds as an empty library; import succeeds and the late error blames your call site. — 1.README 🔇
- Xcode 27 keeps the deprecated GenerationError catch compiling, but runtime errors no longer reach it. — 1.README 🔇
- mlx-swift-lm main is a breaking 3.x that split tokenizer and downloader packages — pin a version. — 1.1
- Experimental utilities change APIs between betas independently of OS releases — 1.1
- Xcode 27 adds Transcript.Reasoning/AttachmentSegment payloads; 26-era switches fall to default or stop compiling. — 1.2 🔇
- A false canImport(_version:) doesn't error — guarded code ceases to exist and the library builds empty. — 1.2
- MLXFoundationModels is empty on the 26 SDK: import and build succeed; 'cannot find MLXLanguageModel' blames your code. — 1.2 🔇
- A rebuild under Xcode 27 changes which catch fires; deprecated GenerationError arms go dead without any diagnostic. — 1.2
- catch GenerationError compiles under Xcode 27 but never fires — new error types drop every tested path into bare catch. — 1.2 🔇
Part 2
- Apple can update built-in guardrails independently of app and OS versions, changing safety without notification. — 2.README
- Beta 5 retyped history from ArraySlice
to Transcript.HistoryView — suffix trims survive, raw-Int… — 2.1 - Exhaustive Transcript.Entry switches break compiling on the 27 SDK; 'fixing' with default: silently drops new cases. — 2.1 🔇
- The .custom segment case the docs list is not present in the beta 5 interface. — 2.1
- Beta 5 declares exactly three Segment cases — .custom vanished between the 2026-07-29 capture and beta 5. — 2.1
- Version matrix: LanguageModelSession.GenerationError is deprecated in the 27 SDK — the error surface moved. — 2.1
- Which error catch fires depends on the building Xcode — rebuild with 27 and GenerationError arms stop matching. — 2.2
- The iOS 27 metadata: overloads drop includeSchemaInPrompt — the knob moved into ContextOptions. — 2.2
- Exhaustive Transcript.Entry/Segment switches from iOS 26 fail to compile on 27 — .reasoning and .attachment are new. — 2.3 🔇
- CustomSegment and its protocol are gone from the beta 5 interface; the custom-segment path no longer compiles. — 2.3
- The 27 SDK adds .attachment segments — code with a default: clause silently routes image segments to 'unknown, ignore'. — 2.5
- The retired 8K comment never reproduced; read contextSize because 27 is dynamic and Simulator can return zero. — 2.6
- The 26.5 GenerationError cases are the before side of the rename — never cite them as the 27 error surface. — 2.6
- No source change needed — rebuilding with Xcode 27 is what silently flips which error types your catches see. — 2.6
Part 3
- history is Transcript.HistoryView since beta 5 — same element type, its own SubSequence, opaque non-Int Index. — 3.1
- Transcript.Entry switches exhaustive on 26 fail to compile on 27 (.reasoning) — add @unknown default deliberately. — 3.1
- The overflow error has two live spellings — TN3193's GenerationError name vs the 2026 LanguageModelError name. — 3.1
- SDK 27 renamed the generation error type; catches written for the earlier namespace need migration — 3.1 🔇
- Session-restore labels differ — Origami uses history: on 27, the older sample transcript: on 26; relation unverified. — 3.1
- Beta 5 retyped history to Transcript.HistoryView; suffix trims survive, but Int indexing breaks. — 3.2
- Contents entry: SkillActivations and the ForEach that stopped compiling. — 3.3
- Heading: SkillActivations and the ForEach that stopped compiling. — 3.3
- Apple documents 4096 as the iOS 27 platform value; a retired unreproduced report claimed 8K — still read contextSize… — 3.4
- PCC supportsLocale/supportedLanguages became async throws in beta 5; a sync capability guard no longer compiles. — 3.4
Part 4
- Contents entry: the double gate — built against the 26 SDK, MLXFoundationModels compiles to an empty library. — 4.2
- Beta 3 renamed SamplingMode cases (.top→.randomTopK) — beta-1 code stops compiling; topK and seeds throw here. — 4.2
- Heading: the double gate, and the empty library. — 4.2
- Built against the 26 SDK, MLXFoundationModels compiles to nothing — errors say 'cannot find', never mentioning SDKs. — 4.2 🔇
- Beta 5 confirms six of the seven response actions; updateCustomSegment is not present in the recaptured interface. — 4.3
- The custom-segment provider path is pre-beta-5 surface; CustomSegment and .updateCustomSegment are absent from beta 5. — 4.3
- Beta 3 made .refusal's explanation required — the old Refusal(debugDescription:) example no longer compiles. — 4.4
Part 5
Part 7
- The artifact is not a function of the recipe — the exporting machine's OS changes what you ship — 7.2
- Same command, same weights: artifacts exported on different host OSes differ ~2x in throughput and memory on-device — 7.2 🔇
- Commit 102f832 renamed CoreAIRunner(from:) to init(bundle:) and the metrics setters — week-old snippets no longer… — 7.4
- Same recipe and wheels export a 2.2x faster artifact on macOS 26 than on the 27 beta — quantized-Linear lowering… — 7.4
- HEAD renamed LanguageModelCapabilities(capabilities:) to an unlabelled init — conformances against older SDKs break — 7.4
Part 8
- OS 27 beta 2 refuses .aimodel files converted with coreai-torch v0.4.0 — published assets must be reconverted with 0.4.1 — 8.1
- input_names/output_names no longer cover buffers — pre-release conversion scripts now fail the count check — 8.1
- Omitted I/O names get FX placeholder defaults — an implementation detail, not a contract, that changes across PyTorch — 8.1
- A PyTorch upgrade renames auto-generated keys or rebinds them to different tensors — pass explicit names everywhere — 8.1 🔇
- v0.4.0-converted artifacts fail to load from OS 27 beta 2 — reconvert with coreai-torch v0.4.1 or later — 8.2
- Custom lowerings depend on private coreai._compiler APIs that can break across wheel versions — 8.2
- Quantized-kernel APIs are narrower than session 330 suggests — the feature ladder is per-point-release — 8.3
Part 9
- Scalar palettization is reproducible; vector palettization is not — identical builds differ — 9.2
- A vector-palettized model differs every rebuild of the identical commit — golden-hash regression tests fail mysteriously — 9.2 🔇
Part 10
- Working pins: coreai-torch 0.4.1+, torch 2.9.0; letting uv bump torch to 2.11 breaks torchvision, killing every export. — 10.2
- A stale egg-info directory or clone working directory can shadow the newer installed wheel — 10.2 🔇
- Breaking change vs pre-release code: input_names now also covers state names; older export scripts mis-bind. — 10.3
- Running python from the coreai-torch clone shadows 0.4.1 with 0.4.0 egg-info; exports silently use the broken version. — 10.3
- The package pins mlc-ai/xgrammar to branch main, not a version; resolve and commit your own revision. — 10.3
- The fork snapshots an older upstream; commit 04a3fd6 upstream already stops pipelined generation when the stream drops. — 10.3
- Pinned file and line citations target an older coreai-models snapshot; re-verify them against a fresh clone. — 10.3
- VLM exports changed from name.llmasset to name directories; scripts globbing the old extension break. — 10.3
Part 11
- MLX hardcodes an undocumented fragment linearisation (kElemsPerFrag); a toolchain change could silently break it. — 11.1
- coreai.authoring Metal-kernel APIs are experimental and subject to change; pin your coreai-torch version. — 11.2
Part 12
- export_function is experimental; .mlxfn files from older MLX versions may not load in future ones. — 12.1
Part 13
- 3.x main is a breaking major: download and tokenization become protocols you must implement yourself — 13.README
- The beta SDK declares a three-argument updateUsage symbol missing from its dylib, causing a launch-time abort. — 13.README 🔇
- The GPU cache API was renamed and both spellings circulate — verify which your version exports — 13.1
- Two ticket(...) spellings for wired memory exist in the repo and one is stale — 13.1
- 27-beta SDK churn: an interface/dylib mismatch escalates from silent drift to a SIGSEGV process abort — 13.1
- SamplingModeKind was renamed mid-beta and the churn is flagged ongoing — re-verify each beta — 13.3
Part 14
- The bridge's core call is private AIProgram._from_mlir_module — any coreai wheel bump can break it without notice — 14.1
- mlx2coreai pins coreai-core b1; b1 bundles fail on Xcode 27 beta 3+ with 'Failed to convert to versioned IR' — 14.1
Part 15
Part 16
- AnalyzerInput.buffer is deprecated — read format and duration via the new iOS 27 properties — 16.1
- The clientIdentifier: prepare overloads are deprecated — migrate off them — 16.1
- Deprecated schemas stay in the enumeration and keep working — deprecation means migrate, not removed — 16.2
Part 17
- Nothing announces itself: a rebuild changes what your catch blocks catch; conversions emit 2.2x-slower artifacts — 17.README 🔇
- Apps built with Xcode 26 keep catching GenerationError until you rebuild with 27; catch semantics change on rebuild — 17.1 🔇
- contextSize is a compiled-in 4096 below OS 27 and dynamic at or above it; hardcoding either number breaks on one side. — 17.1
- What-changed entry: beta 5 retyped Transcript.history and the history session property to Transcript.HistoryView. — 17.1
- Stable fm removes beta quota/PCC syntax; re-check deployment-OS help before migration automation. — 17.1
- catch GenerationError clauses still compile after an Xcode 27 rebuild but stop firing; the catch-all absorbs them — 17.1 🔇
- A wheel built with Xcode 26 permanently lacks image support; ImagePromptError surfaces on the first image call — 17.1
- Xcode 26 gives no build-time signal of the adapter sunset: no attested deprecation, and the packaging CLI still ships — 17.2 🔇
- Xcode 27 diagnoses adapter removal, but dual-target binaries need evaluations for unverified runtime behavior — 17.2 🔇
- MLXFoundationModels compiles only when the trait and the 27-SDK canImport both hold; otherwise it is an empty library — 17.2
- GenerationError was deprecated, not deleted: catch clauses compile but stop firing once you rebuild with Xcode 27 — 17.3 🔇
- TOC pointer: the empty library — a green 26-SDK build of MLXFoundationModels contains nothing — 17.4
- MLXFoundationModels on the 26 SDK: builds successfully and contains nothing — 17.4
- Apple states it twice in-repo: on the 26 SDK MLXFoundationModels builds successfully as an empty library — 17.4 🔇
- SkillActivations dropped RandomAccessCollection in beta 3; the README's ForEach snippet no longer compiles — 17.4
- Build artifacts carry compatibility constraints independent of source; none of these defects appear in a code diff — 17.6 🔇
- TOC pointer: the export host's OS version is an input to the model's on-device performance — 17.6
- Chicken-and-egg: repair tooling on beta-2+ machines runs the same versioned-IR conversion and cannot load the asset — 17.6
- On beta-2+ machines the authoring bytecode reader aborts on the asset, so the published repair snippet cannot load it — 17.6
- coreai-core==1.0.0b2 pins only the Python layer; the OS framework it dispatches to changes with every macOS update — 17.6
- An artifact exported on an older host runs 2.2x slower on device while staying numerically fine; nothing flags it — 17.6
- The lesson: the export host's OS version is an input to the artifact's on-device speed and memory — 17.6
- Pinning 1.0.0-beta3 freezes you against beta-4 renames; the package tracks one Xcode beta and breaks on the next — 17.6
- coreai-models pins xgrammar to branch main, not a version; identical checkouts can resolve different dependency code — 17.6
Docs vs reality¶
Documented behavior differs from what ships — samples that don't compile, wrong signatures, naming mismatches.
Part 1
- Do not hardcode 4096: Apple documents 4096 for iOS 27, but contextSize is dynamic and the third-party 8K device report… — 1.1
- Apple's documented PCC URL 404s; the live path is developer.apple.com/private-cloud-compute/ — entitlement is managed. — 1.1
- Only Core AI's graph compiler is OS-resident; the LLM runtime ships as Swift code in your app, despite Apple's framing. — 1.1
- Session 330 calls the tensor-ops API 'new in 27'; the header floor is 26.2 — only the quantized macro is 27.0. — 1.2
- Docs and session 339 promise watchOS support, but SystemLanguageModel and its types carry no watchOS 27 availability. — 1.2
- Apple's three-arm catch omits SystemLanguageModel.Error, unreachable via LanguageModelError — those failures fall… — 1.2 🔇
Part 2
- Apple's documented nested @Generable example fails macro expansion in Xcode 27 beta 27A5228h; move the nested type to… — 2.2
- Python docstrings leak Swift #/…/# regex delimiters — working tests use bare patterns; do not copy the delimiters. — 2.2
- Apple's ResponseStream snippet does not compile — unbalanced braces, a stray try!, and an undefined variable. — 2.2
- LanguageModelSession.Error is in docs and a forum snippet but no shipping sample — keep the arm, distrust its cases. — 2.2
- Apple's article writes GenerationOptions(samplingMode:); Apple's code and the Python SDK write sampling: — unresolved. — 2.5
- Three names circulate for the availability-testing menu — trust the docs' spelling over transcripts. — 2.6
Part 3
- Utilities package: the README dependency line resolves to nothing and every composed example it ships is inert. — 3.README 🔇
- Docs still list four Segment cases; the beta 5 interface declares three — .custom is not present. — 3.1
- Session 242 defers to 243 for detecting cache invalidation — 243 never mentions a cache metric; only the docs do. — 3.1
- Profile(model:) { } appears in conference write-ups, never in Apple code — the model is applied as a modifier. — 3.2
- Contents entry: the '5000 tokens' ghost. — 3.3
- The README's .package(from:"1.0.0") can never resolve — only prerelease tags exist and from: excludes prereleases. — 3.3 🔇
- Apple's SKILL.md claims summarizeHistory defaults model: — the shipping source has no default; you must pass one. — 3.3
- Heading: the '5000 tokens' ghost — a README trigger the API cannot express. — 3.3
- The package's modifiers use the lossy session-wide history property that session 242 says not to prefer. — 3.3
- README and SKILL.md still claim the conformance beta 3 removed — the shipped ForEach snippet no longer compiles. — 3.3
- The bundled SKILL.md is stale beta-1 with eight verified wrong claims — agents reading it generate broken code. — 3.3
- Evidence note: sessions 242/243 describe both patterns, but no Apple sample implements either with a real tool. — 3.4
- Session 319 and the docs disagree on the quota-simulation menu path and label — prefer the docs, check the other tab. — 3.4
- The package README is out of date — SkillActivations lost RandomAccessCollection; iterate activeSkillNames instead. — 3.4
Part 4
- The PCC article implies any LanguageModel fits the legacy inits — the API types them SystemLanguageModel only. — 4.1
- An Apple doc page stacks .reasoningLevel(.deep) with a redundant ContextOptions(reasoningLevel:) — do not copy it. — 4.1
- Transcript and docs disagree on the quota-simulation scheme page and menu title — the limit-reached option matches. — 4.1
- The README dependency line resolves to nothing — only beta tags exist and SwiftPM from: excludes prereleases. — 4.2
- README's URL 'http://localhost/v1:8000' puts the port in the path — requests actually hit localhost on port 80. — 4.2
- The README claims Linux support, but the repo has no CI, Dockerfile, or platform matrix — structurally unproven. — 4.3
- SKILL.md describes three SwiftPM traits gating features — Package.swift declares none; the claim is fiction. — 4.3
- The prerelease-tag trap: the documented dependency line resolves to nothing — from: excludes beta-only tags. — 4.3
- Session 339's send-metadata-upfront advice breaks tool-calling turns on 27.0 beta — an empty Response entry appears. — 4.4 🔇
Part 5
- Menu strings differ between Apple's spoken narration and its written docs — don't pattern-match one exact wording. — 5.1
- Captions spell the idea tool three ways (GenerateCraftIdeaTool/IdeasTool/generateCraftIdea); the exact name is… — 5.1
- Session 242 defers cache detection to 243, which never names it; the current written documentation supplies the metric. — 5.1
- The Python SDK is 26-generation (macOS 26+) though the session is about macOS 27 throughout — expect capability gaps. — 5.2
- The SDK runs on macOS 26 but the fm CLI does not exist there — the session presents them as one workflow. — 5.2
- The Python SDK lacks PCC, reasoning, and attachments; stable fm no longer supplies the beta PCC route. — 5.2
- The docstring's SystemLanguageModel(temperature:top_p:) raises TypeError — sampling lives on GenerationOptions. — 5.2
- test_composed_prompt_cleanup.py's docstring promises an fd-count regression test; the file has only four mocked unit… — 5.2
Part 6
- Session 335 presents Cohen's kappa as built-in; MetricsAggregator has no agreement statistic — Apple hand-writes 72… — 6.README
- The evaluates trait's second parameter is info: [String: String]; session 298 calls it 'notes' — trust the API spelling. — 6.1
- Reconstructions show func f(results:); the real shape is plain func f() reading EvaluationContext.current.result… — 6.1
- reference returns [String: String] — each pair a labelled prompt section — not the String circulating material claims. — 6.2
- Cohen's kappa is not in the framework despite session 335; Book Tracker hand-writes 72 lines in Statistics.swift. — 6.2
- The doc gestures at 'certain eligibility requirements'; the session states a <2M-downloads bar — a genuine corpus… — 6.3
Part 7
- Doc pages mark three runtime inits watchOS-unavailable while the captured SDK interface declares all three watchOS 27.0 — 7.1
- Delete-while-referenced: reference pages say an error is thrown, the article says deletion is silently deferred — 7.1
- Docs cite layout.scalarCount, which is not public API — an internal-doc leak; compute the element count yourself — 7.1
- Apple's minimumByteCount sample reverses argument order and omits try await on an async throws call — 7.1
- Apple's two image-preprocessing files disagree: premultipliedLast vs noneSkipLast alpha, and one resize is square-only — 7.1
- metadata.platforms omissions are a docs bug; doc watchOS-unavailable notes contradict the captured SDK interface — 7.1
- Orphaned aside on model(for:options:) is a truncated Throws clause mis-rendered as a Note on three API pages — 7.2
- Reference pages and the caching article give opposite answers on deleting an entry a live AIModel still uses — 7.2
- deleteEntry(referencedBy:) repeats the contradictory live-AIModel deletion NOTE — release the model before deleting — 7.2
- coreai-build is not in Xcode-beta.app — it ships in the optional Metal Toolchain component; xcrun caches the miss — 7.2
- The AsyncValue overview's second example does not compile as written — 7.3
- BundleKind has four cases while the repo ships six model families — the mapping is not one-to-one — 7.4
- The shipped SpeechModel actor needs a split bundle no exporter produces — whisper export emits one monolithic .aimodel — 7.4
- CoreAILanguageModel.init's own doc comment contradicts what the code does — a documentation trap — 7.4
Part 8
- The 'three preserved ops' claim is wrong as commonly stated — see the corrected preserved-op list — 8.1
- Naming parameters are keyword-only; the API doc renders them positionally — positional calls raise TypeError — 8.1
- export_fn is keyword-only and required — the API doc shows it positionally and with no hint that it has no default — 8.1
- Apple material shows both runner(**inputs) and runner(dict) calling conventions — pick the dict form the tests use — 8.1
- Session 325 says 4-bit on both encoders; the shipped recipe is asymmetric (image w4/gs32, text w6/gs8) — 8.1
- TorchConverter's mode= parameter is real but absent from the API doc — as is the strip_debug_info escape hatch — 8.1
- Docstring examples still call dump_intermediates — the exported symbol is save_intermediates; suffix is validated — 8.1
- generate-composite-decl docs name the wrong parameter (op_name), omit version, and misstate the return type — 8.2
- Apple ships GatedDeltaUpdate with composite_attrs=[] — the doc page's attribute list does not match the shipped spec — 8.2
- TorchConverter.md renders keyword-only params positionally and omits mode= — code written from the doc raises TypeError — 8.2
- The shipped SAM3 export does not contain session 330's FlashAttention kernel — there is no code to copy — 8.3
Part 9
- The session transcript's claim about EAGER mode does not match the shipped behavior — a discrepancy worth knowing — 9.1
- Talk says 4-bit on the two encoders; the shipped recipe is asymmetric — image w4/gs32, text w6/gs8 — 9.1
- Talk says per-channel scales; the shipping recipe sets enable_per_channel_scale=False and uses grouped-channel… — 9.1
- Return value vs in-place mutation: Apple's own docs give both readings of the casting passes — 9.1
- Casting mutates and returns the same ExportedProgram in 0.3.0; earlier documentation conflicted — 9.1
- Framework page lists seven platforms; every symbol page's platform array omits macOS and Catalyst — a docs-generation… — 9.3
- Session 325 narration says per-channel scales; shipped code sets enable_per_channel_scale=False — both readings are live — 9.3
Part 10
- Apple's skill file recommends einsum SDPA; the shipped iOS code uses per-head permute plus matmul instead. — 10.1
- from_source_model appears only in skill files; shipped coreai-models uses task-specific factories like from_hf. — 10.1
- The WWDC session's segmentation caching story does not match what the shipped CoreAISegmentationEngine does. — 10.1
- The 76% second-inference figure omits device and warm-up protocol, and the shipped engine lacks the caching it assumes. — 10.1
- TorchConverter's API doc shows a bare constructor and never mentions the real mode parameter. — 10.2
- The talk recommends EAGER for weight compression; the repo's recommended default is GRAPH - each fits different jobs. — 10.2
- Talk says 4-bit with per-channel scales on both encoders; the shipped recipe is asymmetric w4/gs32, w6/gs8 without. — 10.2
- The maintainer's snippet assigns strip_debug_info's return value, but it returns None; use the statement form. — 10.2
- Community and guide recipe counts differ; run --list-models because the registry is authoritative — 10.3
- coreai.llm.eval is declared in project.scripts but unconditionally errors with 'Evaluation support is coming soon'. — 10.3
- This contradicts WWDC26 325:241's 'with per-channel scales'; the shipped code sets it False and wins. — 10.3
- COREAI_CHUNK_THRESHOLD is a memory dial and Apple's hint points the wrong way on a high-RAM Mac. — 10.3
- Session 325:241's 'per-channel scales' conflicts with the shipped recipe; the shipped code wins. — 10.3
Part 11
- This guide uses get_mask, but the inspected header has no such API; use is_valid_element instead. — 11.README
- Circulating material calls tensor_offset a descriptor; in the header it is a Tag. — 11.1
- static_slice does not exist in the SDK; the real spelling is a templated slice. — 11.1
- The shipping header's example loop writes a comma where a semicolon belongs; pasted verbatim it will not compile. — 11.2
- Apple's map_iterator example passes the tensor where an iterator is required and drops a semicolon; do not paste it. — 11.2
- execution_threadgroup does not exist; the header admits only execution_threads<1> and execution_simdgroups
. — 11.2
Part 12
- LEARNED_QUANTS.md's DWQ and AWQ defaults don't match the code (1024/8 vs 2048/4; 32/10 vs 128/20); trust --help. — 12.4
- LORA.md tells users to pass --hf-path to mlx_lm.fuse, but the inspected command has no such flag. — 12.4
- The two best sources give different RDMA setup sequences; both are quoted - pick one deliberately. — 12.5
- --output does not exist on the launcher; the real flag is --output-hostfile. — 12.5
- The docs' NCCL example passes --no-verify-script, a flag the launcher does not have. — 12.5
- The example config contradicts CONFIG_DEFAULTS; copying it silently changes schedule values. — 12.6
- Doc bug: LORA.md's upload example passes --hf-path to mlx_lm.fuse; fuse.py declares eight flags and no such option. — 12.6
Part 13
- The 3.x upgrade-notes URL 404s (issue #217) — read Documentation.docc/upgrade.md in the repo instead — 13.1
- MLXCXGrammar and MLXHuggingFaceMacros are targets, not products — briefs listing them as importable are wrong — 13.1
- The upgrade document's own migration table contains stale module names — 13.1
- The bundled skill's loading code is stale against the 3.x API in the same repo — 13.1
- The MLXLLM and MLXVLM README links are genuinely dead — not a transcription error — 13.2
- Session 339's one-argument MLXLanguageModel init does not exist — code written from the session will not compile — 13.3
Part 14
- The public run_aimodel API has no state argument, so it cannot execute the stateful asset its converter produces. — 14.README 🔇
Part 15
- The individual symbol pages disagree with the framework page — Apple docs conflict on this behavior — 15.1
- Apple's docs contradict each other on deleting a cache entry a live AIModel still references — 15.1
- Reference pages say deleting an in-use entry throws; Apple's other doc says deferred — code for both outcomes — 15.1
- Bookmark cleanup hits the same doc contradiction as §7.4 — in-use deletion is documented both ways — 15.1
Part 16
- Familiarity's sign is documented backwards; PFA drops layers with a mere warning; pre-fix Keras 3 analyses nothing — 16.README
- The downloadable SpeechAnalyzer sample is the WWDC25 leftover — stale for the 2026 APIs — 16.1
- Don't verify the 2026 API from the downloadable sample — it compiles and runs but teaches only iOS 26 patterns — 16.1
- Apple's option-enum snippet is missing commas and does not compile as printed — 16.1
- Two Apple pages describe an impossible config: merge progressiveLongDictation by time range, but it emits none — 16.1 🔇
- Session 345 says 'our 2027 releases' while sibling sessions say otherwise — Apple's own year labels conflict — 16.2
- Section flag: places where Apple's docs contradict the observed behavior — 16.2
- The journaling domain's page name and its symbols don't match — know it before URL-hunting — 16.2
- The symbol is AppSchema.JournalIntent (singular) but the domain page says journaling — the mismatch again — 16.2
- Session 240's published sample conflicts with the SDK on this mapping — the interface wins — 16.2
- SnippetIntent shipped in iOS 26 — material presenting it as new this year mislabels the floor — 16.2
- The macOS interface spells only .audio(.nowPlaying) — the session's .workout situation is absent there — 16.2
- Session 345's 'our 2027 releases' conflicts with other sessions' labels — a version-label trap in Apple's material — 16.3
- Session 240's own sample uses per-row annotation — the exact pattern that loses selected and scrolled-off entities — 16.3
- Sessions 345 and 240 use two names for seemingly one representation type — no page reconciles them (G9) — 16.3
- Place content routes via ValueRepresentation/IntentValueRepresentation — concept verified, naming hazard G9 open — 16.3
- The .files domain page never mentions FileEntityIdentifier/FileRepresentation — the recipe came from a forum, not docs — 16.3
- The 'making onscreen content available' article 404s — cited by name in thread 838329 but gone — 16.3
- Every circulating reconstruction of the hydration method has the wrong signature — only the interface shape is real — 16.4
- Session 246 calls searchableItems(forIdentifiers:) new; it's macOS 15.4+ — only the protectionClass overload is new — 16.4
- G8: the .workout situation is absent from the macOS interface — only .audio(.nowPlaying) is spelled there — 16.4
- Matrix: searchableItems(forIdentifiers:) is macOS 15.4+, conflicting with session 246's 'new'; Obj-C hides it from dumps — 16.4
- Session 345 says 'our 2027 releases' three times; 240 and 343 label differently — normalize year labels before citing — 16.4
- The docs' math has Familiarity's sign backwards — higher is more familiar; sort the documented way and results invert — 16.5 🔇
- The notebook reports difference of mean log-scores (log of the ratio) — log the thresholds before comparing — 16.5
- The notebook's FieldRenamer literal is TF1-style 'input_1:0'; TF2 names it 'input_1' — check model.input_layers — 16.5
- Consolidated: Familiarity is higher-is-more-familiar; the docs' math section disagrees — 16.5
Part 17
- The apple-intelligence/private-cloud-compute doc path 404s; the live page is developer.apple.com/private-cloud-compute — 17.1
- Utilities package traps: from: 1.0.0 never resolves, SkillActivations lost its collection shape, API is experimental — 17.1
- Evaluations ships no agreement statistic; the sample's Statistics.cohensKappa is 72 lines of hand-rolled Swift — 17.1
- The README example puts the port inside the URL path, producing a malformed endpoint — 17.1
- .coreaimodel, .aiasset and a coreai-torch convert CLI are fabrications; real forms are .aimodel/.aimodelc directories — 17.1
- The claimed on-device LoRA training API does not exist; the historical adapter workflow trained off-device — 17.1
- The apple-intelligence/private-cloud-compute documentation path 404s; use the shorter private-cloud-compute URL — 17.1
- Docs build Transcript.Response(segments:) but Apple's Origami sample also passes assetIDs; the SDK seems to require it — 17.3
- '8K context on iOS 27' is retired third-party provenance; Apple's TN3193 states 4096 tokens per session — 17.4
- No .coreaimodel, .aiasset or coreai-torch convert exist; real spellings are .aimodel/.aimodelc, both directories — 17.5
- upgrade.md tells you to import MLXLMHuggingFace or MLXEmbeddersHuggingFace; neither module exists in the package — 17.6
- At the inspected revision, migration docs name missing modules; check Package.swift and use MLXHuggingFace. — 17.6
- The utilities README's install line cannot resolve; only prerelease tags exist — 17.6
- README says .package(from: 1.0.0) but only 1.0.0-beta1 and beta3 tags exist; SwiftPM's from: excludes prereleases — 17.6 🔇
API footguns¶
API shapes that invite silent misuse — surprising defaults, order-dependence, overload traps.
Part 1
- A near-miss prewarm(model:transcript:) signature compiles but never binds; the framework's default no-op runs instead. — 1.README 🔇
- supportsGuidedGeneration: is a flag you assert, not a probe — claim it and schema enforcement rests on your server. — 1.1
- Prefill from trimKVCache's returned prefix and honor whether the engine expects the full sequence or suffix — 1.1
- prewarm has a default no-op extension; a near-miss signature never binds and session.prewarm() quietly does nothing. — 1.1 🔇
- A tool referenced in instructions but missing from the toolset can loop indefinitely without an error — 1.1 🔇
Part 2
- .required has no iteration cap; a tool named in instructions but never registered loops forever with no error. — 2.README 🔇
- Transcript.Response's assetIDs is required yet undocumented — Apple's own code passes an array of one empty string. — 2.1
- .required keeps calling tools until you throw from a tool or flip the mode dynamically — there is no default exit. — 2.1 🔇
- GenerationID is stable within one response only — it is not a domain key; matching across responses breaks. — 2.2
- AttachmentLabel output is constrained to be a string, not one of your labels — treat lookup misses as expected. — 2.2
- Apple's corrective-string fallback has a reported failure: the model loops re-calling with invalid args — cap retries. — 2.2
- streamResponse is neither async nor throwing — schema errors surface later, inside the iteration loop, not at the call. — 2.2
- Python stream_response skips the request lock — a stream and respond() can overlap on one session with no error. — 2.2
- Contents entry: .required is a while loop and you own the exit. — 2.3
- Contents entry: the tool you named in instructions but never registered. — 2.3
- toolCallingMode is the only non-defaulted param in the 4-arg init — omit it and you get the iOS 26 three-arg overload. — 2.3
- Heading: .required is a while loop and you own the exit. — 2.3
- Apple verbatim: with required tool calling the model is in a while loop — providing an exit condition is your job. — 2.3 🔇
- Profile body is re-evaluated per request — 7 evaluations across 3 turns measured; read state there, never mutate. — 2.3
- If a tool throws before setting its exit flag, repeated calls remain unbounded; count invocations — 2.3
- Heading: the tool you named but never registered. — 2.3
- Instructions naming an unregistered tool loop with no thrown error — WWDC26 session 243 exists to teach the diagnosis. — 2.3 🔇
- Corrective strings for bad .anyOf args can wedge the model re-calling with invalid args — bound retries yourself. — 2.3
- Throwing from onToolCall stops the whole turn's loop — you cannot reject one tool call and keep the conversation. — 2.3
- Unrecognised model types default to the JSON tool-call parser — Mistral [TOOL_CALLS] reads as text and no tool runs. — 2.3 🔇
- SpotlightSearchTool is stream and accumulator — built inline in the tools array, no reference exists to read results. — 2.4 🔇
- DetectedObject.boundingBox is always top-left; Segment.box flips on macOS — same code, different y per platform. — 2.5
- Two box encodings in one repo — detector emits DETR [cx,cy,w,h], segmenter XYXY; check what your export produces. — 2.5
Part 3
- Profile body ran 7 times across 3 turns — side effects multiply; the unregistered-tool infinite loop also lives here. — 3.README 🔇
- .required never exits by itself — side-effecting tools repeat their work; a call-site options: overrides your loop exit. — 3.README 🔇
- Community count: the DynamicInstructions body ran 7 times across 3 turns — 'each time prompted' understates it. — 3.1
- Heading: the tool named in prose but absent from the toolset. — 3.1
- Heading: the instructions/toolset drift bug. — 3.2
- Instructions naming switchToTutorialMode without registering it loop forever with no error — WWDC 243's central bug. — 3.2 🔇
- A random seed is best-effort, per Apple's own docs — never assert byte-identical output in a test. — 3.2
- .required has no timeout or cap — a never-true exit fills the window and throws contextSizeExceeded many tokens later. — 3.2 🔇
- Heading: the body must be pure — it runs more than once per turn. — 3.2
- Profile body side effects execute an unpredictable number of times — 7 evaluations across 3 turns, community-measured. — 3.2 🔇
- assetIDs is required, undocumented, and Apple passes an array of one empty string — copy it; the 27 SDK hints at more. — 3.2
- A throw from onToolCall aborts the entire turn and rolls the transcript back — no per-call denial exists. — 3.2
- Surface table: the DynamicProfile/Profile body must never mutate — the §6.2 purity rule. — 3.2
- Surface table: DynamicProfileModifier.body follows the same purity rule — write only inside the hook it installs. — 3.2
- Surface table: DynamicInstructions body must stay pure, and history is read-only there (§12.2). — 3.2
- Heading: history is read-only inside DynamicInstructions and Tool contexts. — 3.2
- History is documented read-only inside DynamicInstructions and Tool — what a write there does is an unverified gap. — 3.2 🔇
- Heading: the mutable transcript has a dedicated session error. — 3.2
- Mutating the transcript mid-response is caller misuse with a typed error — guard every assignment on isResponding. — 3.2
- Add one skill with allowsDeactivation and the tool renames to toggle_skill — instructions citing activate_skill break. — 3.3 🔇
- Prompt skills never register as active — isActive(promptSkillName) is false forever, by deliberate design. — 3.3 🔇
- Contents entry: .required is a while loop and you supply the exit. — 3.4
- Heading: the baton tool you named but never registered. — 3.4
- The handoff tool named only in instructions loops forever with no error — session 243 is built around this bug. — 3.4 🔇
- toolCallingMode is the only non-defaulted param in the 4-arg init — omitting it selects the iOS 26 overload. — 3.4
- Heading: .required is a while loop and you supply the exit. — 3.4
- Apple verbatim: with required tool calling the model is essentially in a while loop — the exit condition is your job. — 3.4 🔇
- Profile body re-evaluates per request — 7 evaluations in 3 turns measured; read your route variable, never mutate. — 3.4
- An exit flag alone can leave throwing tools in an unbounded loop; use a plain invocation counter — 3.4
Part 4
- A near-miss prewarm signature compiles but binds the protocol's no-op default — your prewarm is never called. — 4.README 🔇
- catch contextSizeExceeded must precede catch LanguageModelError as a type — otherwise the specific arm is dead code. — 4.1
- The macro expands into your file — miss one of the six required imports and the expansion fails at your call site. — 4.2
- stopStrings:nil silently falls back to extraEOSTokens — pass [] to truly disable; invisible at the call site. — 4.2
- ModelRegistry aliases LLMRegistry in MLXLLM and VLMRegistry in MLXVLM — import both and the name cannot resolve. — 4.2
- prewarm has a no-op default witness — an almost-right signature compiles, never runs, and first requests stay slow. — 4.3 🔇
- Quick reference: prewarm(model:transcript:) defaults to a no-op — your signature must match exactly to be called. — 4.3
- Heading: the near-miss signature that binds the default. — 4.4
- An almost-right prewarm signature compiles, binds the do-nothing default, and the first response is slow forever. — 4.4 🔇
Part 5
- includeSchemaInPrompt: false without a one-shot example leaves neither schema nor pattern — structured output degrades. — 5.1
- _stream_response skips the session request lock every respond path takes; a stream and respond() interleave… — 5.2
- GuideType members are camelCase (maxItems) while factories are snake_case (max_items) — an autocomplete trap. — 5.2
- Dictionary-built GeneratedContent has no native pointer; to_json and is_complete fail on it — 5.2
- Tool validation is bare asserts, disabled under python -O — a tool missing description fails later and less legibly. — 5.2
- ImageAttachment path must be pathlib.Path; a plain str dies on path.is_file() with AttributeError, not a friendly error. — 5.2
- Prompts expand any non-str iterable: a consumed generator retries as an empty prompt; a dict contributes only its keys. — 5.2
- Transcript-loaded tools are historical only; forget to re-pass instances and the replayed session can never call tools. — 5.2
- Manual cleanup of native session resources crashes the interpreter — never call the internal _release() yourself. — 5.2
- session._release() double-frees when GC releases again — EXC_BREAKPOINT/SIGTRAP in libswiftCore.dylib. — 5.2
- except fm.FoundationModelsError misses image failures — PromptError/ImagePromptError subclass plain Exception; catch… — 5.2
- Native cancellation surfaces as GenerationError rather than asyncio.CancelledError — 5.2
Part 6
- Apple's snippet shadows Metric('Match') in the closure — same-name metrics merge or produce results aggregation never… — 6.1
- Metric labels are unchecked strings written twice; a case typo makes #expect read a label that was never registered. — 6.2
- The samples result includes the seeds too — appending it to an existing dataset duplicates every seed. — 6.3
Part 7
- Python load_function raises KeyError for a missing name; Swift returns nil — ported parity tests change shape — 7.1
- preferredStrides/minimumByteCount on an unresolved dynamic descriptor is a programming error — resolve dimensions first — 7.1
- shape/strides come back as Span
: no map/reduce/for-in — the obvious element-count reduce does not compile — 7.1 - Span is non-escapable and not a Sequence — shape.reduce(1,*) does not compile; write your own product helper — 7.1
- Metal-buffer views require shared storage, valid bounds, and synchronization against concurrent writes — 7.1
- InferenceValue.ndArray is a consuming read dressed as a getter — a nil-check consumes the value — 7.1
- The ndArray property consumes the InferenceValue on first access despite reading like a plain getter — 7.1
- if value.ndArray != nil consumes the value — the later real read then yields nothing — 7.1
- Dictionary state views force-unwrap and check exclusivity per iteration; use named arrays or community recursion. — 7.1
- Small MPSNDArray allocations still require the reported 64-byte buffer floor — 7.1
- Segment.box origin flips per platform — Apple's decoder flips Y on macOS; assuming one convention misplaces every box — 7.1
- catch let error as AssetError placed after a bare catch compiles but never runs — keep the bare catch last — 7.1
- Cheat sheet: InferenceValue.ndArray is a consuming read — access it once — 7.1
- NamedMutableViews.take is single-shot — a second take of the same name is fatal — 7.1
- NDArray(descriptor:) may allocate a non-contiguous, hardware-preferred layout — do not assume row-major bytes — 7.1
- shape/strides are Span
, which is not a Sequence — no reduce/map/for-in — 7.1 - Write through mutatingSlice(at:) — other slice accessors do not write back to the array — 7.1
- view(as:) is consuming — taking a typed view ends the tensor's other uses — 7.1
- view
(as:) on a mutable array returns a MUTABLE view — writes go through even where you expected a read — 7.1 - minimumByteCount is a programming error while hasDynamicShape — resolve dimensions first — 7.1
- preferredStrides likewise traps on an unresolved dynamic descriptor — 7.1
- AssetError covers ASSET operations only — inference and cache failures throw other, mostly untyped errors — 7.1
- PreparedModel.clearCache(at:) is coreai-models sample API keyed on a bundle path, not an AIModelCache framework method. — 7.2
- availableKinds varies by device but not by model — a present Neural Engine says nothing about your graph's eligibility — 7.2
- Inside withUnsafeMutablePointer the shape/strides are Span
— not a Sequence, so no reduce; ship a product helper — 7.3 - .aimodel and .aimodelc are directories, not files — file-oriented copy, zip and signing steps mishandle them — 7.4
- autoDetectVariant calls preconditionFailure on an unrecognized bundle — it crashes rather than throwing — 7.4
- Engine variant is a String?, not an enum — the Variant type is private, so typos cannot be caught at compile time — 7.4
- rollback() is @discardableResult and fallible; over-budget calls return false and silently leave grammar state unmoved. — 7.4
- fillBitmask(into:) states its buffer-size contract only in a doc comment; an undersized pointer writes out of bounds… — 7.4
- Sampling applies minP before topP before topK — not the order most stacks use, so identical settings sample differently — 7.4
- SamplingConfiguration.init preconditions, not throws — a topP of 0 from a config or slider crashes the app — 7.4
- DecodingType has exactly one case (.vanilla) — the factory and builder cannot select any custom decoding strategy — 7.4
- Engine selection is only via the variant string — the Variant enum is private and unvalidated at compile time — 7.4
Part 8
- Coverage is per-overload — support for one overload of an op proves nothing about its siblings — 8.2
- mean.dim converts, mean.names_dim doesn't; sum.dim_IntList converts, sum.default is absent from the table entirely — 8.2 🔇
- torch.export.default_decompositions() makes conversion fail — only Apple's get_decomp_table() works — 8.2
- The default torch decomposition table yields unsupported ops — conversion fails; use get_decomp_table() instead — 8.2 🔇
- gather_mm indices must be unsigned ints while torch.topk returns int64 — PyTorch won't complain about the mismatch — 8.2
- Lowering overrides are per-converter-instance and invisible in output — a shared converter object carries hidden… — 8.2 🔇
- Registration ordering matters, and the rule is subtler than 'always register first' — 8.2
- generate_composite_decl inserts version into the supplied dictionary; reusing it retains that mutation — 8.2 🔇
- Composite input_names are parameters and buffers first, then forward args — not your forward signature order — 8.2
- Template substitution is textual — every occurrence of TYPE is replaced, including comments, strings, and MY_TYPE — 8.3
- Templating covers the type, not literals — TYPE sum = 0.0f breaks integer instantiations; template ZERO per dtype too — 8.3
- torch_defn is traced with FakeTensors — any value read like int(idx[i]) or .item() breaks; keep gathers shape-static — 8.3
Part 9
- GRAPH and EAGER are separate implementations with different configs and bugs — not guaranteed to produce equivalent… — 9.README
- A field set to None is not the same as omitting it — the two spell different quantization configs — 9.1
- Graph and eager modes do not produce equivalent quantized models — switching modes changes numerics — 9.1
- Graph mode overrides six ops' qschemes for backend correctness — eager mode performs none of these adjustments — 9.1
- palettize_weights' lut_dtype is positional #2 with no default — docs pass it as a keyword, hiding the trap; XOR rules… — 9.1
- PerTensorGranularity exists twice with the same spelling in different modules — importing the wrong one misconfigures — 9.2
- lut_dtype is positional #2 with no default — pass positionally and your n_bits lands in the lut_dtype slot — 9.2
- uv run implicitly syncs and can clobber group-pinned venv packages — Apple's own AGENTS.md says always pass --no-sync — 9.2
- Import the palettization PerTensorGranularity — not the identically-named quantization one — 9.2
Part 10
- The most common first mistake: pointing a runner at the inner .aimodel when it wants the bundle directory. — 10.3
- macOS wants keyCache/valueCache, iOS wants key_cache/value_cache; copying a name across targets fails at load, loudly. — 10.3
- The coreai-models auto-detect loader crashes on segmenter or speech assets instead of throwing a usable error. — 10.3
- Model output buffers are only valid inside the async with block; call .numpy() before the context exits. — 10.3
- AOT arch strings track device identifiers, not marketing names; a name-matched guess produces an asset that won't load. — 10.3
- expectFrequentReshapes=true on an all-static graph abandons the AOT specialization and segfaults with no error string. — 10.3
- Mistral tool-call detection synthesizes a newline close marker; a multi-line [TOOL_CALLS] array breaks the parser. — 10.3
- ModelBundle.verify() runs only in the llm-runner CLI, not in init; a broken assets map surfaces later, in your app. — 10.3
- position_ids must be the full 0..total-1 vector every call, not just new positions, or RoPE indexing silently breaks. — 10.3
Part 11
- matmul_mode defaults to mode::multiply, not accumulate - see the 3.5 K-loop trap. — 11.1
- matmul2d's default mode is multiply and its exact semantics are not fully settled in the docs. — 11.1
- get_destination_cooperative_tensor has a single no-argument overload; no predicate, no conversion, unlike inputs. — 11.2
- slice(a,b) takes (column,row) while matmul2d_descriptor takes (rows,columns); mixed conventions slice the wrong tiles. — 11.2
- Custom-kernel src is the body only; includes, using-declarations and descriptor constexprs must go in helper_src. — 11.2
Part 12
- A stream is only usable on its creating thread; workers get 'There is no Stream(gpu, 0) in current thread'. — 12.1
- A NumPy array or float on self is not a parameter - never saved or restored - and underscore names are invisible too. — 12.1
- load_weights(strict=False) skips shape checks entirely; mismatched weights load and the model silently misbehaves. — 12.1
- MLX's fp8_e8m0, fp8_e4m3 and fp4_e2m1 are its own structs, not interchangeable with other stacks' formats. — 12.3
- DEFAULT_XTC_THRESHOLD is 0.0 but the CLI default for --xtc-threshold is 0.1 - one of four disagreeing XTC defaults. — 12.4
- --prefill-step-size doubles as the quantized-KV memory knob; tuning one silently changes the other. — 12.4
- generate() returns None, not '', when no text is emitted; .strip() callers crash exactly on the worst inputs. — 12.4
- stream_generate(max_tokens=0) raises UnboundLocalError; for prefill-only, call generate_step and drain the generator. — 12.4
- load_prompt_cache rebuilds classes from mlx_lm.models.cache globals; a custom cache class saves but cannot load back. — 12.4
- The CLI hard-errors on draft/model tokenizer mismatch; the server only warns and proceeds with speculative decoding. — 12.4
- BatchGenerator.insert writes new caches into the very list you passed; held references mutate under you. — 12.4
- --allowed-origins defaults to the string '*', making origin checks substring tests; pass it explicitly for a real list. — 12.5
- ChatCompletionsLanguageModel's literal 'v1' check appends /v1/chat/completions after non-/v1 base paths, producing 404s. — 12.5
- The first successful distributed init wins: later init() or backend='any' calls return the first backend, not a new one. — 12.5
- Dict hostfile entries are read with data['backend'] not .get(); omit the key and the launcher raises KeyError. — 12.5
- Script and model paths resolve on each node, not the launcher; launcher-local paths fail or run stale copies remotely. — 12.5
- --batch-size is the global batch split across N nodes; leave it unscaled and each node trains on batch/N. — 12.5
- Python LoRALinear defaults scale=20.0; the Swift stack's default differs, so ported adapters silently change behavior. — 12.6
- ConcatenatedDataset.getitem writes a _dataset key into the record it returns, mutating your data in place. — 12.6
- --resume-adapter-file loads with strict=False, so misshapen or misnamed weights are silently skipped. — 12.6
- Driving train() directly writes only weights; write adapter_config.json yourself or downstream loads fail. — 12.6
- cosine_decay with decay_steps below iters bottoms the LR out early; the tail of training runs at the floor. — 12.6
- Warmup hands off at warmup_steps+1, not warmup_steps, and the cosine clock restarts there - an LR-path off-by-one. — 12.6
- Avoid --optimizer muon from the CLI; build MultiOptimizer in Python. Muon's doc page 404s though the class exists. — 12.6
- --iters counts micro-steps, not optimizer updates; with gradient accumulation you get fewer updates than you planned. — 12.6
- With --fine-tune-type full, lora_parameters is None and never read; a full config isn't interchangeable with LoRA's. — 12.6
- --batch-size is global and must be scaled by N; unscaled, each node quietly trains on batch/N. — 12.6
- generate() returns None, not '', for empty output, and stream_generate(max_tokens=0) raises UnboundLocalError. — 12.6
Part 13
- skipSpecialTokens defaults to false — decoded text keeps special tokens unless you opt out — 13.1
- SendableBox.consume() fatalErrors on a second call — a one-shot type that crashes instead of erroring — 13.1
- GPU work active during backgrounding triggers an uncatchable Metal abort; cancel and await it on scenePhase. — 13.1
- NSCache eviction isn't coordinated with MLX, and Apple's snippet re-stomps the process-wide cacheLimit on every load — 13.1
- ChatSession is not thread-safe — the source says one task at a time; concurrent use corrupts state unguarded — 13.2
- MLXArray is not Sendable — perform callers must eval() before returning values out or they race the stream — 13.2
- numDraftTokens defaults to 5 via SpeculativeDecodingConfig but 2 via free generate(draftModel:) — economics shift — 13.2
- Swift temperature defaults to 0.6, not 0 — ports assuming Python's greedy default sample stochastically — 13.2
- maxTokens nil means unlimited — deliberate in llm-tool, a runaway generation in an app — 13.2
- The third initializer explicitly disables cache quantization — choose it and kvBits quietly stops applying — 13.2
- prompt.didSet doesn't fire in init — mutating images after chat-based construction desyncs media from messages — 13.2
- stopStrings nil falls back to extraEOSTokens — nil and empty array behave differently — 13.2
- A bare-id load bypasses the registry — no extraEOSTokens or curated defaults; same model, different behavior — 13.2
- gemma's exact-equality rule misses family variants — they fall through to the .json default — 13.2
- Older toolCallFormat versions matched 'gemma' exactly, so Gemma 4 fell through and emitted tool calls as text. — 13.2
- Mixing ToolCallProcessor's two APIs on one instance corrupts its streaming state machine — the source forbids it — 13.2
- A protocol-extension-only ropeOffset would be statically shadowed — subclass overrides silently ignored via existentials — 13.2
- newCache derives cache count from kvHeads.count — an unassigned empty array builds zero caches and crashes — 13.2
- Calling cache.update(...) yourself before attentionWithCacheUpdate double-applies it and corrupts the cache — 13.2
- .required with an empty tool list throws instead of degrading to plain generation — 13.3
- TokenizerInfo.init defaults vocabType .raw; sessions default .byteLevel — hand-built infos silently use wrong semantics — 13.3
- GuidedGenerationLoop.run must not be called from @MainActor — the README's warning is load-bearing — 13.3
- Never hand-build an LMInput — a 1-D input aborts the process; go through the provided constructors — 13.3
Part 14
- The console script omits --batch-size while the Python function accepts batch_size and raises for anything but 1 — 14.1
- Omitting metadata_version defaults it to '0.1' and the reader throws unsupportedVersion — write the string '0.2' — 14.1
- A .aimodel path where a bundle dir is expected throws pointedAtModelAsset — guarding a misleading version error — 14.1
- Capture runs the model twice (trace plus reference) — RNG or dropout diverges unless capture_is_training=False — 14.1
- generate_composite_decl mutates the caller's dict in place — reuse carries state you didn't put there — 14.1
- Never run an iOS-compiled bundle on a Mac — it can wedge the GPU/ANE stack into a watchdog reboot — 14.1
- CoreAILanguageModels.ModelConfig (bundle config) is not the similarly named model configuration — name collision — 14.1
- The two prompt paths have opposite image-placeholder requirements and the same error case — 14.1
Part 15
- Architecture codes track device identifiers, not marketing names — 'iPhone 17 Pro' reads h17p but is h18p — 15.1
- Code comment: match path components exactly — contains('ane') also matches 'gated-deltanet' — 15.1
- The app-group cache init returns nil and Apple's sample answers with fatalError — copy it and config errors crash — 15.1
Part 16
- In update intents nil means both 'clear' and 'untouched' — if-let code silently drops every 'remove the due date' — 16.README 🔇
- finish() alone never terminates the result streams — 'for try await result' waits forever and the stop button hangs — 16.1 🔇
- assetInstallationRequest is nil on already-provisioned devices — force-unwrap and you crash exactly where all is fine — 16.1 🔇
- A local withTaskCancellationShield shadows the Swift 6.4 stdlib function with different generics and no async/sync… — 16.1
- Code comment: the installation request is nil when assets are already installed — never force-unwrap — 16.1
- SpeechDetector.Result is not speech/silence events — the name promises what the stream doesn't carry — 16.1
- speechDetector.results carries only VAD model errors per Apple's docs — subscribe for speech events and get none — 16.1 🔇
- ignoresResourceLimits trades a clean, catchable error for nondeterministic failure at an unknown threshold — 16.1 🔇
- Schemas ship in conversational sets — adopting one intent triggers build errors demanding the rest of its set — 16.2
- All four reminders update intents hit the valueState nil-conflation bug — 'remove the due date' silently no-ops — 16.2
- IntentValueQuery input isn't always scalar — session 240's case is a collection; scalar-assuming code misses it — 16.2
- TransientAppEntity is not a local choice — it forecloses every integration listed in §14.4 — 16.2
- LongRunningIntent requires progress as its liveness signal — never touch progress and assume the intent is killed — 16.2
- valueState exists because nil conflates 'clear it' with 'don't touch it' — the obvious code silently drops clears — 16.2
- Per-row .appEntityIdentifier loses selected and scrolled-off entities — the pattern Apple's sample shows uncaveated — 16.2
- TransientAppEntity silently forecloses three system integrations — a type choice that disables features elsewhere — 16.2
- SyncableEntity with a per-device id compiles cleanly, nothing validates it — Siri still loses entities across devices — 16.2
- LongRunningIntent without progress writes gives no liveness evidence — consequence undocumented; assume killed — 16.2
- Annotate a UUID id with uuidString and entities(for:) gets unmatchable Strings — empty array, Siri quietly moves on — 16.3
- The Now Playing identifier array's order is semantic, not stylistic — 16.3
- Per-row annotation loses selected and scrolled-off entities — annotate the container with forSelectionType — 16.3
- TransientAppEntity forecloses three system integrations — silently, via the type choice — 16.3
- Now Playing identifiers in the wrong order resolve the wrong entity — the order is semantic — 16.3
- Index into a named CSSearchableIndex while other code uses the default and the corpus silently splits — 16.4
- beginBatch/endBatch is not a transaction — partial writes persist; clientState is for resume, not rollback — 16.4
- CSCustomAttributeKey's init is failable — a nil key means the attribute silently never reaches the index — 16.4
- TransientAppEntity cannot be used as an annotation — the constraint that catches people here — 16.4
- The hydration method is a nonisolated non-throwing completion handler — the natural async form never binds — 16.4
- Same object, same uniqueIdentifier on both on-ramps — mismatched ids duplicate entries and break linkage — 16.4
- An infinite Producer hangs forever — introspectors consume all batches and the program stops responding, no error — 16.5 🔇
- MetaKey generic payloads are type-checker-only — a MetaKey[int] happily carries strings at runtime — 16.5
- requested_responses=None requests every layer (~90 on MobileNet, full spatial activations) — always pass a list — 16.5
- ImageResizer size is (width, height), ignores aspect ratio, and asserts 4-D input — 16.5
- Consolidated: an infinite Producer hangs forever — 16.5
Part 17
- ToolCallingMode.required loops tool calls forever unless a tool throws or a DynamicProfile switches the mode — 17.1 🔇
- Call-site .disallowed overrides a tool-allowing profile; the reverse precedence remains unverified — 17.1
- The four-argument GenerationOptions initializer requires toolCallingMode even though its other arguments default — 17.1
- Returning a corrective string for invalid .anyOf arguments makes the model loop re-calling; add a counter and hard exit — 17.1
- The sampling factory is random(top:seed:) but the Kind case is randomTopK; two spellings at two API levels — 17.1
- urlSessionConfiguration is excluded from Configuration ==/hash; a cached executor may carry the wrong session — 17.1
- LanguageModel in the MLX protocol is MLX's type, not FoundationModels'; the name collision satisfies the compiler — 17.2
- default: break on the non-frozen error enum silently swallows every future case; use @unknown default instead — 17.3 🔇
- GeneratedContentParsingError is not a LanguageModelError; guided-generation parse failures skip your ladder — 17.3 🔇
- A misspelled canImport module or undefined condition makes an #if silently false and deletes the guarded code — 17.4 🔇
- Misspelled canImport, undefined conditions and wrong version forms all make gates quietly always-false — 17.4
- loadFunction returns nil for a missing name but throws for a load failure; try? collapses two different diagnoses — 17.5
- Span is not a Sequence; Sequence-based map, reduce, and iteration patterns need different access — 17.5
- Outputs.remove(_:) is destructive: read an output twice (log, then return) and the second read is silently nil — 17.5
- InferenceValue.ndArray looks like an ordinary getter but consumes the value and transfers ownership on access — 17.5
- Segment.box origin is bottom-left on macOS and top-left on iOS; detection's boundingBox uses yet another convention — 17.5
- A borrowed state view cannot outlive its owning state collection — 17.5
- More-menu hand-offs require opening the gauge report before recording the event to investigate — 17.5
- mmap_dir is a CoreAI export path; deleting its mapped files invalidates the model weights — 17.5
- Translation table: Core ML output reads become destructive Outputs.remove(_:) — take each value exactly once — 17.5
- A bundle holds two different metadata.json files at different depths; only the inner one is the producer fingerprint — 17.6
- strip_debug_info mutates in place and returns None; transcribing the snippet as an assignment nulls your program — 17.6
- expectFrequentReshapes=true on an all-static graph abandons the AOT specialization, recompiles on device and segfaults — 17.6
- FM macro expansions need six imports at the call site; missing one yields 'cannot find type' inside generated code — 17.6
General cautions¶
Warnings and considerations that are not themselves silent failures.
Part 1
- Constructing PrivateCloudComputeLanguageModel without the granted entitlement terminates with fatalError. — 1.README
- Pipelined Core AI samples on-GPU with no logits; a correct provider must throw on schema requests, not approximate. — 1.1
- BYO-model @Generable leaves MLX or sequential Core AI; MLX keeps logit tooling without a slower engine. — 1.1
- Correction: MLX does run on iPhone via mlx-swift — only the ANE is closed to it; an earlier community claim erred. — 1.1
- Every table warning is one fact: pipelined Core AI has no logits, so no @Generable — read 5.1 before relying on a row. — 1.1
- The system model is sealed — no weight swaps, no custom LoRA on OS 27; specific models mean Core AI or MLX. — 1.1
- Past 4,096 tokens you need PCC (32K) or a Core AI/MLX model; the Core AI branch carries the @Generable caveat. — 1.1
- Reasoning needs PCC levels or a Core AI/MLX reasoning model; SystemLanguageModel does not reason. — 1.1
- Core AI's fastest engine has no logits so .guidedGeneration is off — and every Core AI benchmark used that engine. — 1.1
- Apple FM measures 0.11 J/token, ~2x better than GPU runtimes and ~4x the CoreML/ANE path; bundles are engine-dependent. — 1.1
- The robust ANE win is GPU exclusivity, not speed — inference off-GPU keeps the UI's GPU free; MLX cannot reach this. — 1.1
- Meta note: every warning row above is the same Generable-vs-fastest-engine fact wearing a different hat. — 1.1
- Bring your own model and you lose @Generable exactly when picking the fastest backend — stated nowhere by Apple. — 1.1
- Source retention numbers conflict (38% vs 64-67% MLX); keep only the qualitative point — GPU throttles, ANE holds. — 1.1
- Version mistakes here yield empty libraries, dead catches, evaporating #if code, error -1 — rarely a real diagnostic. — 1.2 🔇
- PCC's Small Business condition is reconstructed — on the dev site, in no WWDC transcript; confirm before planning on it. — 1.2
Part 2
- Cross-reference: session lifetime ties into §7.3's warning that Instruments traces store prompts unencrypted. — 2.1
- Instruments traces store every prompt and response unencrypted — a shared .trace file leaks user text verbatim. — 2.1 🔇
- Pointer: the entry payload parameter is undocumented — see the assetIDs callout in §2.5. — 2.1
- GenerationGuide.count has both Int and ClosedRange overloads — both exercised in compiling Apple sample code. — 2.2
- Where the .anyOf constraint is lost — schema serialisation, grammar compilation, or matcher — remains unresolved. — 2.2
- Heading: do not stream in the background — backgrounded streams invite rateLimited; Apple says use respond(to:). — 2.2
- The 1044→700 token saving is Apple's demo on unspecified hardware — reuse the shape of the claim, not the numbers. — 2.2
- Heading: three Python-side silent failures, led by options= being dropped when generating= is passed. — 2.2
- Apple verbatim: recordings capture and store all Foundation Models prompts and responses — guard your traces. — 2.2
- The tool-calling Instruments template records prompts and responses — treat .trace files as user data; never commit. — 2.3
- Community-measured: small models emit tool JSON the framework rejects (decodingFailure) — in-tool baton-pass is shaky. — 2.3
- The 27.0 SDK declares exactly four Attachment image inits — CGImage, CIImage, CVPixelBuffer, imageURL; no UIImage. — 2.5
- Source note: the coffee/generative-game and SpeechAnalyzer samples surface in searches but are stale iOS 26 evidence. — 2.5
- Read-first: most defects here do not throw — string refusals, out-of-band guardrail changes, incomplete catch ladders. — 2.6
- The availability sample is an iOS 26 project — cite it as the 26 baseline only, never as 2026 guidance. — 2.6
- Evidence note: every symbol in the degradation function is cited upstream; refusal detection is deliberately defensive. — 2.6
- Refusal-string detection is a heuristic, not an API — Apple documents only the shape of a refusal. — 2.6
Part 3
- Group Labs ship no caption track — cite Apple's written Q&A summary as paraphrase, never as an engineer's words. — 3.1
- Sample logging line: prints a KV cache hit-rate warning so prefix changes show up during development. — 3.1
- Scope: trimKVCache(to:) is a community-fork Core AI primitive, not a Foundation Models API you can call. — 3.1
- Attribution: the prefix-reuse numbers are one community Mac run (qwen3-0.6b); exact hardware and build unstated. — 3.1
- Attribution: the cannot-prefix-cache conclusion is one community implementation's finding, not an Apple statement. — 3.1
- Saved transcripts contain everything typed and generated — debug-gate the writer and treat the files as sensitive. — 3.2
- Surface table: session.properties has an SDK-verified setter whose runtime semantics remain an open gap. — 3.2
- Read-first: foundation-models-utilities has two commits and only prerelease tags — beta software, not a library. — 3.3
- .anyOf still can't hard-constrain skill names — Skills defends by throwing ParsingError on unrecognised ones. — 3.3
- That .disallowed withholds tool definitions is verified provider behaviour — Apple's own stack is unverified. — 3.4
- PCC quota reports only reached/approaching/below — no percentages or counts; developers asked for more and got none. — 3.4
- Only .string(_) appears as a value wrapper anywhere in the corpus — .number and .bool are unverified gaps. — 3.4
- Source note: the coffee/generative-game and SpeechAnalyzer samples are not cited as 2026 evidence — stale iOS 26 era. — 3.4
Part 4
- Core AI prefix-cache trimming is a community fork API; do not treat it as an upstream Apple capability. — 4.README
- Heading: you cannot build a usage meter. — 4.1
- The quota API exposes three coarse states and no numbers — progress bars and request counters cannot be built. — 4.1
- Utilities release independently of the OS and contain emerging APIs; pin and review their package versions. — 4.1
- Source note: the coffee/generative-game and SpeechAnalyzer samples are excluded as stale iOS 26 evidence. — 4.1
- Source note: where transcripts and docs disagree (menu strings, context size), this guide prefers the docs. — 4.1
- Passing capabilities yourself makes you the author — declare only what the checkpoint honours, or the guard inverts. — 4.2
- additionalHeaders invites hardcoded API keys — session 339's credential warning applies when you hold the key. — 4.2
- Only CoreAI's compiler/executor is OS-resident — the LLM runtime is Swift you compile into the app. — 4.2
- After a backend swap the transcript is re-templated by the new model — reasoning and tool dialects may not survive. — 4.2
- A custom segment is a compatibility boundary — other executors rightly throw unsupportedTranscriptContent on it. — 4.3
- Scope note: two APIs here (trimKVCache, prefixReuseFeedsFullSequence) are community-fork additions, not Apple's. — 4.4
- Heading: unresolved conflict — whether Apple's own Core AI adapter shares the prewarm near-miss bug. — 4.4
- Read-first: trimKVCache(to:) and prefixReuseFeedsFullSequence come from a community fork patch, not Apple. — 4.4
Part 5
- Instruments records unencrypted prompts and responses; use fixtures and keep trace files out of source control. — 5.README
- The Python SDK exposes the OS-26 feature set, without PCC, BYO backends or the newer session controls. — 5.README
- No one here ran Xcode 27 Instruments; UI claims trace to the session or preserved direct Apple documentation. — 5.1
- The code-along targets macOS Tahoe/Xcode 26 — treat its Playground UI details as 'at least true in 26', not 27. — 5.1
- LanguageModelFeedback attachments carry the full session transcript — consent, no auto-upload, scrub before sharing. — 5.1
- Recording a trace turns FM logging on; read the Record Anyway dialog before clicking. — 5.1
- Starting a trace enables prompt/response capture in the clear for the recording — get consent and scrub before sharing. — 5.1
- The transcript-recorder JSON files contain the full transcript — apply the same consent and scrubbing rules before… — 5.1
- The coffee-game and SpeechAnalyzer samples are iOS 26-era harvests — do not read them as evidence of 27 behaviour. — 5.1
- Evidence in this guide is the weakest of Parts 1-6 — read the provenance warning before trusting details. — 5.2
- The Swift/Python parity fixtures differ (Int .range vs prose-bounded nested type) — parity is schema-level only. — 5.2
- The Python SDK lacks the tool interception needed to reproduce consent-gated execution — 5.2
- Transcripts are user words: exporting them off-device is a data-collection decision — consent, redaction, retention. — 5.2
- Symptom-to-cause table of the SDK's non-throwing failures: dropped options, failed seed casts, ignored guides, hung… — 5.2
Part 6
- TOC: the guide's collected silent failures — shrinking datasets, collapsed distributions, mismatched configs, orphan… — 6.1
- ScoreDimension text differs between production and calibration on purpose — 'same evaluator' means same type, not same… — 6.1
- Give the judge only a few alignment examples; a longer list overfits the alignment score and hides misalignment… — 6.1
- A broken evaluation still produces a number — the number you decided to trust; the catalogue below runs worst-first. — 6.1
- TOC: silent failures in judge alignment (section 19). — 6.2
- numeric(_:) takes [Double: String]; Apple's sample writes integer literals that coerce — both work, dumps say Double. — 6.2
- Section index: eight silent failures in judge alignment, from the positional join to inherited FM failure modes. — 6.2
- Judge calls are model calls — guardrails, context, availability apply; 12% failed calls silently corrupt the… — 6.2
- TOC: ToolCallEvaluator requires ModelSubject(value:transcript:); omitting the transcript throws missingTranscript… — 6.3
- ToolCallEvaluator needs ModelSubject(value:transcript:) — without the transcript no trajectory can be scored. — 6.3
- ModelSubject(value:) without transcript: still builds; ToolCallEvaluator throws missingTranscript — loud but… — 6.3
- The 58%-to-100% tool-eval lift is Apple's 12-sample letter-counting demo — a framework demo, not an expected benchmark. — 6.3
- Only sample-attested call shapes are generated; the combined (ordered:unordered:disallowed:) init is real but… — 6.3
- Two Apple samples are deliberately uncited: coffee-game and SpeechAnalyzer are unrefreshed iOS 26/WWDC25 leftovers. — 6.3
Part 7
- Part-wide evidence note: verify signatures against the SDK dump — Core AI ships no Apple sample code — 7.README
- Scope note: signatures rest on doc prose and shipped repos, not Apple sample code — verify before relying — 7.1
- expectFrequentReshapes has no documented default; the recorded device fixture observed false — 7.1
- Community swift-lm hand-rolls an async mutex for run serialization — single-author alpha code, not Apple guidance — 7.1
- Xcode's model viewer shows ? for a dynamic dimension; NDArrayDescriptor.shape reports -1 — same fact, two spellings — 7.1
- Community input validator: check unexpected/missing inputs, scalarType, rank, and per-axis -1-or-equal before run() — 7.1
- run() requires a mutable view for every state — omitting any state is an error; drive allocation from stateNames — 7.1
- Community state allocation: MTLBuffer sized by minimumByteCount with .storageModeShared, then memset to zero — 7.1
- Community swift-lm defines rich typed asset errors (shape/dtype/state mismatches) the Apple runtime does not give you — 7.1
- specialize() and init have no progress, stages, or cancellation contract — your Preparing UI must be indeterminate — 7.2
- Compile-time figures are single-author beta measurements — trust the shape (jetsam can kill compilation), not the… — 7.2
- Throughput figures here are one community author plus one shipping app, self-declared uncontrolled — attribute… — 7.2
- Verified absences: /documentation/updates/coreai 404s and the Updates hub carries no Core AI entries — 7.2
- Whole block is community-measured on beta software under uncontrolled conditions — cited because nothing else exists — 7.2
- Apple ships 21 export recipes but zero performance numbers — the community bench table is the only data, treat as such — 7.3
- Pipelined Core AI ties/beats MLX on dense models — but it's int8 vs 4-bit, a ship-config comparison, not iso-precision — 7.3
- Upstream fixed generation continuing after stream drop; the community measurement describes a pre-fix snapshot. — 7.3
- Beta KV-write regression report; closure and current stable remediation are separate observations. — 7.3
- Noema's host-cache design: KV rides as plain I/O because the ANE compiler rejects in-graph indexed KV writes — 7.3
- Write-mask workaround status: Mac GPU verified; iPhone GPU and ANE re-isolation still pending — 7.3
- Prefix-reuse section is a community fork of coreai-models — mechanism corroborated upstream, API and numbers are not — 7.3
- Community trimKVCache drains in-flight generation first, then clamps the processed-token counter — nothing is cleared — 7.3
- trimKVCache protocol default returns -1 (unsupported) so callers degrade safely to full re-prefill — 7.3
- Caller algorithm: track the exact fed token sequence and clamp reuse to commonPrefixLength minus one — 7.3
- Prefix-reuse numbers: qwen3-0.6b on an unstated Mac model and OS — treat the hardware as unverified — 7.3
- The model-selection conclusion derives from one community implementation — not an Apple claim — 7.3
- Known limits: the pipelined trim path is unverified (SIGTRAPs in GrowingLogitsBuffer); short chats see little gain — 7.3
- Numerics debugger pairs only iOS/iPadOS/macOS 27+ — no visionOS, tvOS or watchOS despite framework support — 7.3
- The benchmark tool measures LLMs; the catalog has no published non-LLM quality or latency figures — 7.4
- Apple's own code disagrees on VLM sub-model loading (sequential vs async let) — load sequentially until resolved — 7.4
- All of §6.3-6.4 is community work: a 3-file fork commit on a pre-SAM3 snapshot, not upstream Apple code — 7.4
- The structure-to-compute mapping is apple/coreai-models loader policy, not a Core AI framework routing contract — 7.5
Part 8
- Series-wide evidence note: zero Apple sample code — guides rest on shipped repo source, docs prose, and SDK dumps — 8.README
- Verify numeric parity on the exact shipped Core AI asset, not output shapes alone — 8.1
- Keep shipped-asset parity against eager and exported PyTorch at production shapes — 8.1
- The Neural Engine path threads K/V as plain I/O, not Core AI state — register_buffer KV advice is GPU-only — 8.1 🔇
- AIModelAsset.load only reads the header — compilation and its cost land lazily inside the executable() context manager — 8.1
- Compare eager PyTorch, the decomposed exported program and the exact Core AI asset shipped — 8.1
- Preview-only env vars gate debug metadata — set them before conversion or tooling loses attribution — 8.1
- Scope note: how far MoE gather_mm support does not extend — read before assuming coverage — 8.2
- MoE on GPU/ANE delegates is combination-dependent — Qwen3-MoE ships, but support is not universal — 8.2
- Externalization needs the live nn.Module via add_pytorch_module — add_exported_program has no externalization path — 8.2
- Externalization is not weight streaming — it neither reduces export RAM nor mmaps; that is a separate PyTorch technique — 8.2
- One word, two mechanisms: ExternalizeSpec preserves op boundaries; multi-entrypoint conversion splits programs — 8.2
- Exercise square and asymmetric shapes, non-integral cast inputs, and production value boundaries — 8.2
- Apple's own end-to-end custom-kernel tests are currently disabled — device coverage is thinner than the suite implies — 8.3
- Community figures here are single-author, self-declared uncontrolled, on beta OSes — attribute, never launder — 8.3
Part 9
- Evidence ladder note: zero Apple sample code — shipped repo source outranks docs and talks throughout this part — 9.README
- Table of contents pointer to the consolidated silent-failures section — 9.1
- The 'dynamic' range calculator cannot be exported — finalize() raises NotImplementedError naming each affected module — 9.1
- Annotation limits: chains longer than 2 raise, and sequential matching requires each op type in the chain to be unique — 9.1
- Archive holds opposite int8 orderings for different tensor roles — int8 is the safe floor; which int8 is empirical — 9.1
- Consolidated index of this guide's quantization silent failures — 9.1
- The talk's third row has no number — 'a fraction of the size' is unquantified; don't invent one — 9.1
- Contents pointer: the ANE rank-5 ceiling section — 9.2
- Contents pointer: consolidated silent failures — 9.2
- Beta-era measurement with an identified but unconfirmed mechanism — record toolchain versions with every sweep result — 9.2
- Two opposite int4/int8 findings measured at different dates on different roles — do not flatten them into one rule — 9.2
- Author's caveats: quick-driver tok/s ~10x too slow, only the ratio is valid; flagship int4 has a known quality cost — 9.2
- The one-flag experiment is one author's result on one model family — verify on your own model before adopting — 9.2
- 128 eval samples: a 1.5-point difference is inside noise — trust the ordering, not the magnitudes — 9.2
- Consolidated index of palettization/pruning silent failures — 9.2
- ResNet50 PTQ numbers rest on 128 eval samples (896 calibration) — indicative, not conclusive — 9.2
- Community table is a single-author archive with self-declared uncontrolled benchmarks — not Apple figures — 9.2
- 2.18x dense-int4km ratio: author says absolute tok/s are ~10x too slow — only the ratio is valid — 9.2
- Contents pointer: consolidated silent failures — 9.3
- Matrix legend: warning-marked cells are supported only with the caveat named in the referenced section — 9.3
- int16 sits in the TensorOps enum but the Metal-language type map has no int16 mapping — the int16 oddity — 9.3
- uint8 on the ANE is uncertain — Apple's rule file names only fp16/int8/int16 as ANE compute dtypes — 9.3
- int4 is storage, not compute — the int4b_format Metal type is gated behind a feature macro — 9.3
- uint4 mirrors int4: storage-only, with the same Metal feature-macro gate — 9.3
- MXFP4 emit is validator-enforced: per-block-32 with E8M0 scales, or ValueError — nothing else counts as MXFP4 — 9.3
- k-means palettes: eager-mode only, with a caveat on the recipe path (§2.5) — indices store as sub-byte ints — 9.3
- Apple accepted a known quality regression to avoid a silent compute-unit fallback — the ranking this guide argues for — 9.3
- Two different version numbers are both correct — they answer different questions; report both, not one — 9.3
- OS 27 multi-plane tensors: compute/render usage only, one-byte data elements, no rank-0 — keep a software fallback — 9.3
- No API reports NAX support — MLX infers it from GPU architecture generation; there is no supportsFamily query — 9.3
- MLX ships its own FP4/FP8 bit-manipulation structs — distinct from Xcode 27's Metal tensor datatypes — 9.3
- NAX changes which algorithm is selected (its own split-K), not just which kernel — it is not a drop-in accelerator — 9.3
- --quant-predicate works only with --q-mode affine and needs down_proj modules — otherwise a ValueError — 9.3
- AWQ/GPTQ loading supports only 4-bit checkpoints and rejects g_idx keys; unsupported combinations raise. — 9.3
- Failure #8 is by design: int4 is storage — the runtime dequantizes to fp16/half for arithmetic; nothing to fix — 9.3
- The one-line check: if you targeted the ANE, confirm the viewer's Compute types show no float32 — 9.3
- The Xcode model viewer itself requires the Metal Toolchain, which is not installed by default — 9.3
- Summary asymmetry: storageTypes and operationDistribution carry counts; the compute-side listing does not — 9.3
- Ahead-of-time compiled assets still need device-side specialization; the remaining work depends on model and hardware. — 9.3
- Consolidated index of format-related silent failures — 9.3
- The M5 talk's baselines differ per claim — M4 for images, M1 for video; cite the baseline with the number — 9.3
- ResNet50 PTQ row: int8 and FP8-E4M3 land within ~2.4 points of fp32 — the most directly useful format-choice datum — 9.3
- Methodology: curl via sosumi.ai preserves verbatim signatures the rendered docs sometimes reflow — 9.3
- 111432 is a Tech Talk, not a WWDC session — cite it accordingly — 9.3
Part 10
- Scope note: Core AI has no compiling first-party samples, so verify every signature in this part before trusting it. — 10.README
- Evidence note: no Apple samples or doc updates exist for this framework; claims rest on repos, headers and community. — 10.1
- TOC pointer to the coreai-torch 0.4.0 IR-location incident and its provenance. — 10.2
- Never run an iOS-compiled bundle on a Mac: it can wedge the GPU/ANE stack into a watchdog reboot (community-reported). — 10.2
- The Core AI Debugger's paired-device list omits visionOS, tvOS and watchOS; whether it attaches there is an open gap. — 10.2
- The only benchmarker test upstream is skipped; use benchmark numbers for ranking modules, not for publishing latency. — 10.2
- Per-module timings from benchmark_coreai_program are directional only. — 10.2
- The conversion incident is community-reported with an Apple-maintainer resolution; retain that attribution — 10.2
- Intermediate filenames are community-reported; the audit script depends only on Apple-named metadata.json. — 10.2
- Apple maintainer fix for the 0.4.0 compiler failure: strip_debug_info, then save the updated asset. — 10.2
- Scope note: signatures in this guide come from shipped repos and community evidence, not Apple samples. — 10.3
- Pipeline diagram: after AOT compiling you must hand-edit the assets map in metadata.json. — 10.3
- The .missingAsset error text doubles as fix instructions; read it before debugging. — 10.3
- get_c4 imports undeclared datasets and tqdm; activation quantization raises ImportError with an install hint. — 10.3
- cpu_only() exists for numeric parity checks only; community measured ~9x slower than default() on a DiT. — 10.3
- load_intermediates validates the directory suffix and raises if you point it anywhere else. — 10.3
- Apple's two compression claims measure different things; they are not in conflict - keep baselines straight. — 10.3
- The shipped macOS LLM preset uses eager mode, so it cannot use KV-cache quantization; graph mode is required. — 10.3
- remove_functionalization imports private coreai._compiler dialect modules; pin versions, it can break any release. — 10.3
- Community rule: never execute an iOS-compiled bundle on a Mac - it can cost a watchdog reboot, not an afternoon. — 10.3
- The fastest engine throws on guided generation: @Generable needs per-step logits the pipelined path never exposes. — 10.3
- The pipelined engine also lacks forcedContinuation, so MMLU-style continuation scoring is impossible on it. — 10.3
- Only an LLM benchmark tool exists in the repo; no latency or quality numbers are published for non-LLM models. — 10.3
- Checklist: never execute an iOS-compiled bundle on a Mac. — 10.3
- A second hidden knob: --bucket-size maps to COREAI_QUERY_BUCKET_SIZE; zero disables it. — 10.3
- Correction: MLX does run on iPhone GPUs via mlx-swift; only the ANE is closed, and FM integration is not exclusive. — 10.3
- mlx2coreai is a community MIT project at v0.1.1 with 11 commits, not Apple tooling; it vendors one Apple BSD file. — 10.3
Part 11
- Scope note: session 330 material and circulating names diverge from shipped headers; verify against the SDK first. — 11.README
- The Metal kernel skeleton was not compiled or executed; validate it against headers and a CPU reference. — 11.README
- The 4-bit path is a pointer cast to tensor
; the 26.x matmul2d op does the unpacking itself. — 11.1 - MLX writes cooperative tensors through unchecked operator[] and never calls is_valid_element, relying on known layouts. — 11.1
- TOC: NAX is new and still settling; expect churn. — 11.2
- Never hardcode the MetalToolchain cryptex path; the version token differs per machine - resolve via xcrun. — 11.2
- NAX is new and still settling; expect kernel, gate and semantics churn across releases. — 11.2
- The headline speedup is one matmul shape on one machine; do not carry it into a different context. — 11.2
Part 12
- Scope note: the MLX stack moves weekly; pin versions or every dated claim in this part may have drifted. — 12.README
- Scope note: signatures below are verified against source and docs; check the evidence ladder before trusting. — 12.1
- The mx.metal.* memory spellings are deprecated and print to stderr on first call; use the top-level equivalents. — 12.1
- Compiled-step comparison assumes determinism; capture and seed random state when checking a sampling step. — 12.1
- The applegpu g/s suffix-to-product mapping is disputed between MLX source and community; don't identify products by it. — 12.1
- cross_entropy's reduction defaults to 'none' and accepted literals are unverified; omit it and average yourself. — 12.1
- Scope note: verify signatures below against source; the NAX story is new and evidence is mixed. — 12.2
- The M5 material is a launch Tech Talk, not a WWDC session; weigh its numbers accordingly. — 12.2
- Do not write a blanket '26.2 required'; Apple's own narrated version ladder skips 26.2 entirely. — 12.2
- MLX's g/s suffix table and community observation disagree; use the suffix for buffer sizing, never product ID. — 12.2
- Do not use mx.metal.device_info(); the mx.metal.* family is deprecated and forwards with a stderr notice. — 12.2
- Each Apple M5 speedup uses a different baseline; a number without its baseline is meaningless. — 12.2
- Every figure here is Apple-published with hardware and OS unstated beyond 'M5'; don't generalize. — 12.2
- Fused SDPA is inference-only on Metal; training deliberately uses the unfused path, which is what benchmarks measure. — 12.2
- Correction: Gemma 4's global layers are head_dim 512, not 256; a clean A/B showed no change at 32K/64K. — 12.2
- The fused grid-sample speedup is MLX's own published number with hardware unstated; re-measure on your machine. — 12.2
- Scope note: quantization numbers below carry mixed provenance; check each one's sourcing before quoting. — 12.3
- The routed-only read numbers are community-measured (john-rocky, partly agent-generated repo), not Apple-published. — 12.3
- Scope note: flag names below were verified against argparse declarations, not the docs. — 12.4
- GGUF export supports only llama, mixtral and mistral in fp16; other model types raise ValueError. — 12.4
- Scope note: server signatures verified from source at a pinned commit; PyPI lags main by months. — 12.5
- Freshness: NAX code paths are new and moving, with three correctness fixes within days of writing. — 12.5
- --host 0.0.0.0 exposes a server with no authentication; anyone on the network can drive your model. — 12.5
- HTTP exposes no logits, so @Generable guided generation is unavailable on this path; use tools plus your own validation. — 12.5
- Ring backend restriction: send and recv work only between ring neighbours, not arbitrary ranks. — 12.5
- Counterweight mlx#3830: FAST_SYNCH can deadlock a Metal fence and lock the GPU until reboot; unset, the watchdog fires. — 12.5
- Not all models support pipeline parallelism; check before planning a pipelined topology. — 12.5
- Apple's distributed speedup comes with its own caveat - it depends on setup; quote the caveat with the number. — 12.5
- 180 to 600 tok/s are the session's only absolute figures; every other distributed claim is a ratio. — 12.5
- The RDMA port forum report is community-reported with unknown status and no replies captured. — 12.5
- --mlx-path must not already exist and there is no --force; delete the previous output directory first. — 12.6
- Dropout fires only in training mode; train() and evaluate() toggle it, so know which mode your loop left the model in. — 12.6
- The memory-constrained path's loader accepts only .jsonl with a text field (or one alternate); other formats fail. — 12.6
- mlx_lm.perplexity takes no --adapter-path; fuse the adapter first to measure it this way. — 12.6
- lm-eval with --limit 200 across eight tasks is a smoke test, not a benchmark; don't publish those numbers. — 12.6
- Publish the adapter alongside the fused model; it's two orders of magnitude smaller and others can rebase it. — 12.6
- mlx_lm.server's own startup banner says it is not recommended for production; treat it as a dev tool. — 12.6
- This section is project READMEs only — nothing in it was cloned, run or measured; treat flag names as pointers to check. — 12.6
Part 13
- SerialAccessContainer and SendableBox are package-scoped — reimplement the pattern or use ModelContainer — 13.1
- Streams always end with a .info event carrying stopReason and timings — rely on it, but don't copy llm-tool's fatalError — 13.1
- Evidence on the EXIF fix conflicts between research passes — reported as conflicting, not smoothed over — 13.1
- Scope note: trust no signature below without the stated verification caveats — 13.2
- Returning a string for an unknown tool (not throwing) is the right default — the model can read the failure and retry — 13.2
- keep:4 attention sinks make rotating caches unquantizable/unmergeable in Python; the Swift guard is unverified — 13.2
- gpt-oss attention sinks are incompatible with quantized SDPA — a family-specific hard stop — 13.2
- Detection-script print: caches without rollback or prefix reuse make speculative decoding unsafe — 13.2
- Detection-script print: rotating layers make trimmability temporary — it lapses once the window wraps (#424) — 13.2
- Detection-script print: surfaces the kvBits and quantizedKVStart combination so the trade-off is visible — 13.2
- Sample output: rotating layers present — trimmability is temporary (issue #424) — 13.2
- swift test does not work on this package — use xcodebuild with -skipPackagePluginValidation (and -skipMacroValidation) — 13.3
- Scope note on the logger: some drops surface only at debug level — logging bounds what it can save you from — 13.3
- The mapper's precedence ladder exists to avoid a silent failure — internalise it before writing your own — 13.3
- MLXDownloadProgress lives and dies with the adapter's gate — disable the trait and dependent UI stops compiling — 13.3
- Batching forced tokens with a populated cache hits an MLX causal-mask bug — the loop feeds them one at a time — 13.3
- The vendored xgrammar is pinned at v0.1.30 — upstream fixes past that version are absent — 13.3
- Attribution: supportsLogits and the CoreAIExecutor error string come from community reads, not Apple docs — 13.3
- The backend differential is community-measured from a single setup — treat as protocol, not truth — 13.3
Part 14
- Read-first note: this part rests on source reads of community bridges, not Apple documentation — 14.README
- No WWDC transcript is cited anywhere in this part — nothing here has Apple-session backing — 14.README
- Signature-trust scope note — verify against your checkout before relying on anything below — 14.1
- mlx2coreai writes only kind:'llm' — no VLM path exists; use Apple's exporter or swift-lm for vlm bundles — 14.1
- Shape-dependent Python branches produce two divergent traces and the probe raises — no data-dependent branching — 14.1
- The two backends differ by one (steps vs steps+1) under --grow-context — two hand-written copies of one contract — 14.1
- The community zoo is single-author, benchmarks self-declared uncontrolled — process guidance, not Apple fact — 14.1
- Core AI conversion is not byte-deterministic (measured) — never verify a pipeline by hashing artifacts — 14.1
- metadata.json can embed your build machine's absolute paths — the zoo shipped one; audit what you emit — 14.1
- Cite BENCHMARKS.md as a protocol, not a dataset — n=1 numbers on specific hardware — 14.1
- No WWDC transcript is cited in this guide — the 2026 session corpus does not cover these bridges — 14.1
Part 15
- Read-first note: claims here mix Apple docs with community measurement — check the attribution before acting — 15.README
- Do not copy the quoted Background Assets keys into a 27 project — one developer's 26-era config for a removed feature — 15.1
- Status note: thread 836810 is answered by Apple staff — what's missing is the capability, not the answer — 15.1
- There is no NPU priority entitlement or API — Apple staff confirmed on thread 833666 — 15.2
- Read the attribution first: community-measured on beta OSes — protocol, not gospel — 15.2
Part 16
- Read-first: two planning-level facts gate everything in this part — learn them before scoping work — 16.README
- The AppEntity files recipe is community device evidence, without a verified official resolution. — 16.README
- Two expected things don't exist: a text-to-speech API and any 2026-API sample project — plan around both — 16.1
- SpeechTranscriber has no ContentHint — the custom-language-model path binds only to DictationTranscriber — 16.1
- iOS 26 sample code typed to SpeechTranscriber — the same shape applies to the other transcriber classes — 16.1
- Don't add Task.checkCancellation() to the display loop — its job is to ignore cancellation until the stream ends — 16.1
- Custom-vocabulary lever 3 works only with DictationTranscriber — eligibility is decided before you start — 16.1
- datagenerator is the sample's own executable target — Apple ships no CLI for custom-LM training data — 16.1
- There is a documented cap on simultaneous analyzers — expect insufficientResources and design queueing — 16.1
- Nothing in apple/coreai-models makes the encoder/decoder split SpeechBundle demands — no speech BundleKind; dead end — 16.1
- No performance number exists for CoreAISpeech or any non-LLM Core AI model — the only benchmark tool is LLM-only — 16.1
- The sample page is cited only as evidence that it is stale — 16.1
- Apple sample is iOS 26/WWDC25 material — cited only for the baseline and labelled as such — 16.1
- Symbol-name trust note: verified against the SDK interface — re-check before reusing elsewhere — 16.2
- Scope note: the third schema tier matters more than its billing suggests — 16.2
- Payoff 2 of interaction donations is a hard-scoped limit, not a general capability — 16.2
- Session 345 explicitly does not cover UndoableIntent, IntentModes or SnippetIntent — don't cite it for them — 16.2
- Session 344 published no code block — every listing attributed to it is transcript reconstruction — 16.2
- Symbol-name trust note for this guide — verify before porting names — 16.3
- Draft identity exists, but a verified hand-off still needs a real file payload — materialize first — 16.3
- Whether .appEntityIdentifier takes an optional is unverified — but the compiler tells you; explicitly not silent — 16.3 🔇
- In-memory content must be written to a file before the FileRepresentation hand-off — the step stays necessary — 16.3
- The coffee/game and SpeechAnalyzer samples are stale WWDC25 leftovers — never cited as 2026 evidence — 16.3
- Session 344 has no published code — listings from it are reconstructions from narration — 16.3
- Symbol-name trust note for this guide — 16.4
- Evidence-class warning: this on-ramp's claims rest on thinner evidence — read the section accordingly — 16.4
- Don't adopt AppEntity solely for indexing — it drags in a Siri-facing surface you must then maintain — 16.4
- Indexing is not annotation — descriptive on-screen content alone builds the wrong layer; the line drawn once — 16.4
- IntentValueQuery serves Siri only — path-2 content is invisible to SpotlightSearchTool; no configuration reaches it — 16.4
- Consumer surface note: the demo's consumer was the Fitness app's suggested-playlists list — 16.4
- Donate only UI-originated interactions, never Siri-originated — the rule against feeding the ranking loop back — 16.4
- Get plain indexing working and verified before building consumers — everything downstream depends on it — 16.4
- Treat the six performance numbers as documentation claims, not citable measurements — 16.5
- All images must share H×W×C — mismatches raise DNIKitException; differing sizes need a custom Producer — 16.5
Part 17
- Group Labs ship no caption track — cite Apple's written Q&A summary as paraphrase, never as an engineer's words. — 17.1
- TensorOps availability is per-symbol, not a blanket 26.2; quote each header annotation as a header annotation — 17.1
- Mutating session.transcript during an in-flight request throws the new transcriptMutationWhileResponding error — 17.1
- Pointer: watchOS 27 beta 2 has an Apple-confirmed build break, covered in the checklist's section 10 — 17.1
- The Evaluations forum sample contains only three threads, so community coverage is limited — 17.1
- Core AI ships zero Apple sample-code projects; unlike Foundation Models there is no first-party compiling reference — 17.1
- Apple's own data: detailed prompts raise generation-error rates via context pressure; terse prompts yield excess items — 17.1
- Whether the concurrency/thermal restriction also covers SystemLanguageModel is unanswered on the forums — 17.1
- Custom LoRA adapters are removed outright; the LanguageModel protocol succeeds the goal, not the train-a-delta mechanism — 17.1
- Meta note: this section collects every silent failure in the 26-to-27 migration into one table — 17.1
- SwiftTranscriptionSampleApp is a WWDC25 leftover, named only so nobody mistakes it for 2026 evidence — 17.1
- FoundationModelsCoffeeGame still targets iOS 26.0; cite it only as the before column, never as 2026 API — 17.1
- Repeated audit result: the coreai documentation index contains zero sample-code projects — 17.1
- Session 241's transcript says 'Our 2027 release' while every OS reference is 27; do not write '2027 release' — 17.1
- Three unresolved unknowns about legacy adapters under iOS 27, each paired with a safe default — 17.2
- The whole adapter-pipeline section is 26.x history; do not build new work on it — 17.2
- The leak cleanup is rm -rf on a system path from Recovery Mode; confirm the volume identifier and keep a backup — 17.2
- Evidence scope: the 26.5 interface proves only the before state and the 27.0 beta only the after — 17.3
- The 26-era CoffeeGame sample is deliberately not cited as 2026 evidence; it shows only the before shapes — 17.3
- A dual-SDK CI matrix that only compiles misses load-time crashes; load and run the binary on-device per beta seed — 17.4
- Support matrix: simulators validate compile and launch only; behavioral results need physical 27 hardware — 17.4
- Core AI succeeds Core ML for neural networks only; decision trees and tabular pipelines stay on Core ML by design — 17.5
- TOC pointer to the guide's collection of failures that do not announce themselves — 17.5
- Sub-byte and float8 Swift view mappings are undocumented; keep public I/O in float32 or float16 — 17.5
- Section heading for the Core AI failures that do not announce themselves: compute units, drift, caches, miscompiles — 17.5
- Validate numeric parity at the conversion boundary with the exact shipped asset — 17.5
- Compare the saved asset with eager and decomposed export using separate error budgets — 17.5
- states: requires a mutable view for every declared state; omitting any produces an error — enumerate stateNames first — 17.5
- The 76% multi-function saving is Apple's demo number with no device or protocol stated; treat it as an existence proof — 17.5
- Debug locations caused historical artifact incompatibility; keep debug metadata for development builds only. — 17.5
- Verified: 0 sample-code entries across all 312 indexed Core AI symbols; no first-party compiling reference exists — 17.5
- Span
is not a Sequence: no shape.last; use shape.count and manual index arithmetic in the shim — 17.5 - MLState maps to states: mutable views, and every declared state must be supplied or the call errors — 17.5
- .aimodel replaces .mlmodel/.mlpackage and is a directory; file-oriented scripts must treat it as a bundle — 17.5
- .aimodelc is also a directory; the per-architecture compiled output is a bundle, not a single file — 17.5
- The 0.4.0 asset break was debug-only metadata — weights and program were fine — which is why the repair is cheap — 17.6
- coreai-torch only warns beyond torch 2.13.0 and proceeds; exports made with newer torch are unvalidated — 17.6
- Mode.RELEASE just ships less metadata surface; it is no compatibility promise against future versioned-IR changes — 17.6
- Pinning an older export host conflicts with beta tooling needs; plan two machines or a reversible upgrade procedure — 17.6
- AIModel.specialize reports no progress and no cancellation contract; large models block minutes with nothing to show — 17.6
- Conversion is not byte-deterministic (a rebuild differed by 492 bytes); content_hash proves identity, not equivalence — 17.6
🔇 = the guide marks this as an explicit SILENT FAILURE callout.