Large-Module Audit ================== Thirty-three modules in ``mixle`` exceed 1,500 lines. Size alone is not a defect, and this audit is **not** a mandate to split them. Its purpose (worklist A1.7) is to record, for each large module, what it owns, the state it carries, the optional dependencies it touches, its hot paths, its serialization hooks, and where a *safe* extraction boundary lies — so that a future change can be scoped without a blind refactor. The governing rule, restated from :doc:`support-policy`: **refactor a large module only where it removes a demonstrated defect or enables isolated testing.** Do not split stable numerical code merely to satisfy a line-count target — the EM kernels and forward/backward recursions below are load-bearing and bit-checked, and re-slicing them risks a correctness regression for no user-visible gain. The set of modules audited here is pinned by ``mixle/tests/large_module_audit_test.py``: a new module that crosses 1,500 lines, or an audited entry that is deleted, fails that test until this page is updated. How to read an entry -------------------- * **Responsibilities** — what the module owns. * **Stateful globals** — module-level mutable/registry state (the first thing to check before extraction). * **Optional imports** — heavy dependencies reached lazily; base import must not require them. * **Hot paths** — the numerically load-bearing routines; treat as bit-checked, change with parity tests. * **Serialization** — round-trip hooks (``to_json`` / ``from_json`` / encoders); a schema-visible surface. * **Extraction boundary** — the safe seam, or "leave as-is" when no clean seam removes a defect. Latent sequence and mixture families ------------------------------------ These follow the canonical six-type contract (Distribution / Sampler / Accumulator / AccumulatorFactory / Estimator / DataEncoder). Their bulk is the vectorized ``seq_update`` / ``seq_log_density`` EM machinery and, for several, compiled Numba kernels. They share one extraction principle: the compiled kernels and the data encoder are the only clean seams; the distribution/estimator pair is a single numerical unit. ``mixle/stats/latent/hidden_markov.py`` (5,308) * **Responsibilities:** the principal HMM path — distribution, scaled forward/backward, Baum-Welch EM, terminal/terminal-value likelihoods, Dirichlet chain prior. * **Stateful globals:** only ``TypeVar``\s (``T``, ``E1``, ``E2`` …); no mutable registry. * **Optional imports:** none at this layer (the compiled kernels live in ``_hidden_markov_numba_kernels.py``, already a separate module). * **Hot paths:** ``_hmm_forward_ll``, ``seq_log_density``, ``seq_update``, ``kernel``, the Numba route. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the Numba kernels are already extracted. The terminal-state and terminal-value likelihood blocks are the next candidate seam **if** a defect ever localizes there; absent that, leave as-is — this is the most parity-tested numerical code in the tree. ``mixle/stats/latent/tree_hidden_markov_model.py`` (2,990) * **Responsibilities:** tree-structured HMM; Numba forward/backward, Baum-Welch, posteriors, Viterbi. * **Stateful globals:** ``TypeVar``\s and shape aliases only. * **Optional imports:** none (Numba kernels inline as module functions ``numba_*``). * **Hot paths:** ``numba_seq_log_density``, ``numba_baum_welch``, ``numba_posteriors``, ``numba_viterbi``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the ``numba_*`` kernel group is the clean seam (mirror ``hidden_markov``'s split into a ``_..._numba_kernels`` module) — worth doing only alongside a kernel change. ``mixle/stats/latent/structured_hmm.py`` (3,320) * **Responsibilities:** HMM with pluggable transition operators (dense / low-rank / sparse / block-diagonal / banded), 24 classes. * **Stateful globals:** ``_DENSE_FB_NUMBA`` (compiled-kernel handle). * **Optional imports:** ``jax``, ``numba``. * **Hot paths:** forward/backward, ``seq_update``, ``seq_log_density``, ``logsumexp``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the ``TransitionOperator`` family (already an internal class hierarchy) is the natural module split — a genuine isolated-testing win, low numerical risk. ``mixle/stats/latent/lookback_hidden_markov_model.py`` (2,096) * **Responsibilities:** the lookback-window HMM — a typed rewrite of a since-removed untyped sibling module — forward/backward and Baum-Welch EM over a bounded lookback horizon, terminal-state/value likelihoods, and (as of the conjugate-prior fix) a Dirichlet chain prior mirroring ``hidden_markov.py``'s own MAP path. * **Stateful globals:** only ``TypeVar``\s (``T``, ``E0``, ``E1``); no mutable registry. * **Optional imports:** none at this layer (the compiled kernels live in ``_hidden_markov_numba_kernels.py``, shared with ``hidden_markov.py``). * **Hot paths:** ``seq_log_density``, ``seq_update`` / ``seq_update_engine``, and the MAP branch inside ``estimate`` (``_hmm_map_probs`` plus Dirichlet posterior propagation, added alongside ``get_prior`` / ``set_prior`` / ``model_log_density``). * **Serialization:** ``dist_to_encoder`` / ``seq_encode``; two backward-compatible aliases (``LookbackHiddenMarkovModelAccumulator`` / ``...AccumulatorFactory``) at module scope. * **Extraction boundary:** leave as-is; the prior/MAP machinery just added mirrors ``hidden_markov.py``'s own inline placement rather than introducing a separable module — the file crossed 1,500 lines to reach that parity, not through unrelated growth. ``mixle/stats/sequences/markov_chain.py`` (2,755) * **Responsibilities:** Markov chain distribution/estimator, Dirichlet prior, stationary distribution, gradient-fit state. * **Stateful globals:** ``TypeVar``\s only. * **Optional imports:** none. * **Hot paths:** forward, ``seq_update``, ``seq_log_density``, ``kernel``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** leave as-is; the gradient-fit state (``_MarkovChainGradientFitState``) is the only separable piece and is small. ``mixle/stats/latent/mixture.py`` (2,348) * **Responsibilities:** the general finite mixture — responsibilities, weight prior, EM. * **Stateful globals:** ``TypeVar``\s only. * **Optional imports:** none (Numba referenced through the compute layer). * **Hot paths:** responsibility ``logsumexp``, ``seq_update``, ``seq_log_density``, ``kernel``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** leave as-is; the prior-construction helpers (``mixture_prior`` and friends) could move to a ``_priors`` helper but that is cosmetic, not defect-driven. ``mixle/stats/latent/lda.py`` (1,966) and ``mixle/stats/latent/labeled_lda.py`` (1,837) * **Responsibilities:** LDA and label-supervised LDA — variational E-step, alpha updates. * **Stateful globals:** shape aliases only; no registry. * **Optional imports:** none. * **Hot paths:** variational fixed point, ``seq_update``, ``seq_log_density``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the shared alpha-update math (``update_alpha`` exists in both) is a real duplication seam — a small shared helper would remove copy drift; safe, defect-adjacent. ``mixle/stats/combinator/conditional.py`` (1,965) * **Responsibilities:** conditional-distribution combinator (feature → response) and its accumulation. * **Stateful globals:** shape aliases only. * **Optional imports:** none. * **Hot paths:** ``seq_update``, ``seq_log_density``, ``kernel``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** leave as-is; the two module-level stat helpers are already factored. ``mixle/stats/graphs/temporal_graph_grammar.py`` (4,424) * **Responsibilities:** temporal graph-grammar family (37 classes: motifs, labeled/unlabeled variants). * **Stateful globals:** ``_EPS`` only. * **Optional imports:** none at import (graph backends reached lazily). * **Hot paths:** emission log-likelihood, ``seq_update``, ``seq_log_density``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the labeled vs unlabeled variant families are separable, but they share the motif and alignment helpers; split only if a variant grows an independent defect surface. ``mixle/stats/latent/integer_hidden_association.py`` (1,843) * **Responsibilities:** integer hidden-association models over grouped-count word sets. * **Stateful globals:** encoding/statistic ``TypeVar``\s (``E0``--``E4``, ``SS1``, ``SS2``) only, plus the engine-kernel registration performed by ``_register_int_hidden_association_engine_kernel``. * **Optional imports:** Numba, reached through the compute layer. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``seq_update_engine``, and the ``numba_seq_log_density`` / ``numba_seq_update`` pair. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the ``numba_*`` kernels are the only clean seam, as elsewhere in this section; the distribution/estimator pair is one numerical unit. Leave as-is absent a defect. ``mixle/stats/latent/integer_probabilistic_latent_semantic_indexing.py`` (1,723) * **Responsibilities:** integer PLSI — the EM fixed point over document/topic/word factors. * **Stateful globals:** ``T1``/``SS1`` aliases, plus ``_register_int_plsi_engine_kernel``'s registration. * **Optional imports:** Numba, through the compute layer. * **Hot paths:** ``fast_seq_log_density`` / ``fast_seq_update`` and their ``seq_*`` entry points. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``; ``IntegerPLSIEncodedData`` is the payload. * **Extraction boundary:** ``IntegerPLSIEncodedData`` and the ``fast_*`` kernels separate cleanly from the estimator; a real seam, worth taking only with a defect that localizes there. ``mixle/stats/latent/heterogeneous_pcfg.py`` (1,828) * **Responsibilities:** PCFG with heterogeneous terminal emissions — inside/outside recursions, termination certification, quantized index construction. * **Stateful globals:** none. * **Optional imports:** none at this layer. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``backend_seq_log_density``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** ``PCFGTerminationCertificate`` and ``_HeterogeneousPCFGQuantizedIndexBuilder`` are already self-contained and are the seam if one is ever needed; the recursions themselves are a single unit. ``mixle/stats/sequences/integer_markov_chain.py`` (1,972) * **Responsibilities:** integer Markov chains with optional lagged transitions, including the explicitly non-generative scoring mode (``NonGenerativeIntegerMarkovChainError``). * **Stateful globals:** ``E1``/``E2``/``SS1``/``SS2`` aliases only. * **Optional imports:** none. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``seq_update_engine``, ``backend_seq_log_density``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** leave as-is. The lag handling threads through encode, score and update together; separating it would split one contract across two modules. ``mixle/stats/multivariate/multivariate_gaussian.py`` (1,911) * **Responsibilities:** full-covariance Gaussian six-type contract, the covariance ridge and its repair disclosure, the robust Cholesky self-heal, the opt-in conditioning receipt, and the conditioning-gated shift-anchored moment track. * **Stateful globals:** ``_LAST_REPAIR`` (a one-slot channel from ``_robust_cho_factor`` to the constructor, drained immediately). * **Optional imports:** ``scipy.linalg`` (required at this layer), ``scipy.stats`` lazily for cdf/quantile. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``_robust_cho_factor``, ``_anchored_pooled_covariance``, ``backend_stacked_sufficient_statistics``. * **Serialization:** ``__pysp_getstate__``/``__pysp_setstate__`` (parameters only; derived caches recomputed), ``dist_to_encoder``/``seq_encode``, and ``MultivariateGaussianSuffStat.__reduce__``. * **Extraction boundary:** the anchored-moment helpers (``_needs_anchor``, ``_consistent_anchored_moments``, ``_anchored_mean_offset``, ``_anchored_pooled_covariance``) are the one clean seam, shared in spirit with the diagonal and univariate Gaussian families. ``mixle/stats/multivariate/diagonal_gaussian.py`` (1,624) * **Responsibilities:** diagonal-covariance Gaussian six-type contract, per-coordinate variance floor and its repair disclosure, and the same conditioning-gated shift-anchored moment track. * **Stateful globals:** none. * **Optional imports:** ``scipy.stats`` lazily for cdf/quantile. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``_anchored_pooled_variances``. * **Serialization:** ``dist_to_encoder``/``seq_encode`` and ``DiagonalGaussianSuffStat.__reduce__``. * **Extraction boundary:** the anchored-moment helpers, jointly with the full-covariance module's. ``mixle/stats/multivariate/integer_multinomial.py`` (1,586) * **Responsibilities:** integer-keyed multinomial over a bounded support. * **Stateful globals:** ``SS0``/``D``/``E0``/``E`` aliases only. * **Optional imports:** none. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``seq_update_engine``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** leave as-is; the six-type contract is already the minimum unit here. ``mixle/stats/combinator/sequence.py`` (1,679) * **Responsibilities:** iid sequence laws plus the explicitly non-generative sequence score modes (``NonGenerativeSequenceError``), including the length-support reasoning. * **Stateful globals:** ``T``/``E1``/``E2``/``E`` aliases and the two proof limits ``_INFINITE_INTEGER_LENGTH_SUPPORTS``, ``_FINITE_LENGTH_PROOF_LIMIT`` (constants, not mutable state). * **Optional imports:** none. * **Hot paths:** ``seq_log_density``, ``seq_update``, ``backend_seq_log_density``, ``backend_stacked_log_density``, ``expected_log_density``. * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the length-support proof helpers are the one separable piece; the generative and score-only paths must stay together, since their divergence is the contract. ``mixle/stats/bayes/conjugate.py`` (1,669) * **Responsibilities:** conjugate-prior posteriors derived from the exponential-family map, one class per conjugate pair, plus the ``_NO_CLOSED_FORM`` fallback marker. * **Stateful globals:** ``_NO_CLOSED_FORM`` (a sentinel). * **Optional imports:** ``scipy`` (special functions), reached lazily. * **Hot paths:** posterior updates and ``point_estimate``; per-observation, not per-batch. * **Serialization:** posterior parameters round-trip through the owning distribution. * **Extraction boundary:** one module per conjugate family would be a clean split, but the shared exponential-family derivation is what keeps them consistent — leave as-is. Probabilistic-programming surface --------------------------------- ``mixle/ppl/inference.py`` (4,490) * **Responsibilities:** posterior inference for the PPL — conjugate, Laplace, VI, MCMC routes. * **Stateful globals:** several **registries** — ``_CONJUGATE``, ``_CONJ_LOGM``, ``_HIERARCHICAL``, ``_PRIOR_DICT_BUILDERS``, ``_EXPECTED_PRIOR_FAMILY`` (dispatch tables; the first thing to preserve). * **Optional imports:** ``torch``. * **Hot paths:** ``seq_log_density``, ``kernel`` (through the fitted posteriors). * **Serialization:** ``dist_to_encoder`` / ``seq_encode``. * **Extraction boundary:** the conjugate-posterior registry (tables + their builders) is a clean module of its own, separable from the Laplace/VI/MCMC numeric routes — a real isolated-testing win. Move the registries as a unit so dispatch stays in one place. ``mixle/ppl/core.py`` (3,317) * **Responsibilities:** the PPL authoring DSL (``Field`` / ``Group`` / ``Net`` / ``Conv`` / ``Transformer``) and the fitter registry. * **Stateful globals:** ``_ROUTE_CAVEATS``, ``_CMP``, ``_RESIDUAL`` plus the fitter registry populated by ``register_fitter``. * **Optional imports:** ``torch``. * **Hot paths:** ``forward``, ``seq_log_density``. * **Extraction boundary:** the neural predictors (``_NeuralPredictor`` / ``Net`` / ``Conv`` / ``Transformer``) are the torch-touching subset and a natural split from the pure-DSL field/group core. Compiled-kernel code generation ------------------------------- ``mixle/stats/compute/fused_codegen.py`` (2,438) * **Responsibilities:** the fused-kernel source generator — per-family ``LeafTemplate``\s (scalar, vector, matrix, tabulated, categorical, chain), plan analysis (``analyze``/``fusible``), source emission for the one-pass scorer and E-step (sequential and chunk-parallel prange variants), the secure disk-cached ``_njit`` loader, and the data/parameter marshalling that feeds generated signatures. * **Stateful globals:** the ``_TEMPLATES`` registry (append-ordered; matching is first-hit, so registration order is part of dispatch semantics) and the ``_COMPILED`` / ``_ESTEP_COMPILED`` kernel caches keyed by ``(plan.signature, parallel)`` — plus the on-disk module cache under ``MIXLE_FUSED_CACHE_DIR`` with its ownership/symlink checks. * **Optional imports:** ``numba`` — reached lazily inside ``_njit``; importing this module must stay numba-free (the freeze-rollup resolver depends on that, guarded by ``HAS_NUMBA`` at its call site). * **Hot paths:** every generated ``_fused`` / ``_estep`` kernel; parity is pinned by ``generated_kernel_parity_test.py``, ``fused_codegen_test.py``, ``fused_parallel_test.py`` (ULP / bit-stability receipts), and ``fused_chain_test.py`` — treat template ``row``/``acc`` fragments as bit-checked and change them only with those suites green. * **Serialization:** none — kernels are runtime artifacts; the disk cache is a per-user performance cache keyed by source digest, never a schema surface. * **Extraction boundary:** the leaf templates (registrations plus their param/table builders) are the clean seam — they are data, not machinery, and moving them to a ``_templates`` module would halve the file without touching emission. The emitter + marshalling + cache trio is a single numerical unit; split only against a demonstrated defect. Infrastructure and facade ------------------------- ``mixle/lifecycle.py`` (1,702) * **Responsibilities:** the ``Model`` facade (fit/deploy/load, provenance and integrity checks) and ``propose`` — automatic model-family selection and its held-out verified-frontier scoring. * **Stateful globals:** none (module-level constants only). * **Optional imports:** none directly (delegates tabular record handling to ``mixle.data.sources.pandas_source``, reached only when the caller's data is already pandas). * **Serialization:** ``Model.deploy`` / ``Model.load`` — the JSON-first, pickle-fallback artifact format, including the ``model_sha256`` integrity check and the ``_fit_provenance`` / ``_numerical_repairs`` envelope re-attachment on decode. * **Extraction boundary:** ``Model`` and ``propose`` are two largely independent halves sharing only the tabular-record helpers (``_tabular_records`` et al.); a real seam, but split only if one half's test surface needs isolating from the other's. ``mixle/inference/estimation.py`` (2,422) * **Responsibilities:** the ``optimize`` / ``fit`` / ``best_of`` front door — data encoding, model proposal handoff (``_maybe_structured_model``), the fused/standard EM drivers, and the schedule/objective plumbing. * **Stateful globals:** none (module-level constants only). * **Optional imports:** ``torch`` (gradient-fit path), reached lazily. * **Hot paths:** ``optimize``'s fused-step loop (``_local_fused_step`` / ``_engine_fused_step``) — change with LL-parity tests against the standard loop. * **Serialization:** none directly (delegates to the model's encoders). * **Extraction boundary:** the structure-proposal gate (``_maybe_structured_model``) and the EM-driver loops are separable seams; extract only to remove a demonstrated defect, per the audit's own rule. ``mixle/inference/glm.py`` (1,895) * **Responsibilities:** the GLM front door (``glm``) across the exponential-family link/family set and its robust standard-error variants (HC0-HC3, with their leverage/rank diagnostics), ``robust_regression`` (Huber/Tukey IRLS and its degenerate-fit breakdown disclosure), the penalized-regression trio (``ridge_regression`` / ``elastic_net`` / ``lasso``), and ``quantile_regression``. * **Stateful globals:** none (module-level constants only -- the floors/tolerances/fractions gating the HC2/HC3 leverage guard and the robust-regression breakdown disclosure; none mutable). * **Optional imports:** none. * **Hot paths:** ``glm``'s IRLS loop and its HC2/HC3 leverage computation (rank-masking is parity-sensitive -- see the campaign-eight/D-0208 fix to how it handles a rank-deficient design); ``robust_regression``'s own IRLS loop and its breakdown-disclosure signals (``_robust_weight_collapse`` / ``_robust_response_point_mass``, also D-0208). * **Serialization:** none (``GLMResult`` / ``RegressionFit`` / ``PenalizedResult`` are plain, non-round-tripped dataclasses). * **Extraction boundary:** ``robust_regression`` and its breakdown-disclosure helpers (``_response_robust_scale`` through ``_robust_breakdown_explanation``) are already a self-contained seam from ``glm``, the penalized-regression trio, and ``quantile_regression``. The file crossed 1,500 lines through three consecutive rounds of disclosure-heuristic repair on that one function family (D-0208's own campaign-eight fix wave), not through unrelated growth elsewhere -- extract only if that family needs an isolated test surface of its own, not as a line-count exercise. ``mixle/stats/__init__.py`` (2,426) * **Responsibilities:** the ``mixle.stats`` facade — lazy ``__getattr__`` re-exports, capability registration, and the ``load_models`` / ``dump_models`` model-collection serialization entry points. * **Stateful globals:** ``_INTERNAL_SUFFIXES`` plus the lazy-export and capability tables. * **Optional imports:** none (that is the point — the facade must import in a bare environment). * **Serialization:** ``to_json`` / ``from_json`` (``load_models`` / ``dump_models``). * **Extraction boundary:** the builtin-compute-metadata and lazy-capability registration blocks (``_register_builtin_compute_metadata`` / ``_register_lazy_module_capabilities``) can move to a ``_registration`` helper, leaving ``__init__`` as thin re-export glue. Low risk, improves import readability; do it when the registration tables next change. ``mixle/utils/automatic/profiling.py`` (3,301) * **Responsibilities:** automatic-modeling data profiling — marginal/pairwise structure detection. * **Stateful globals:** tuning constants ``_MIXTURE_EM_CAP``, ``_NUMERIC_MODEL_MARGIN_BITS``, ``GOF_ABSTAIN_PVALUE`` (thresholds, not mutable state). * **Optional imports:** none. * **Extraction boundary:** the goodness-of-fit / entropy scoring helpers are separable from the profile dataclasses; a defect-neutral tidy, not urgent. ``mixle/utils/parallel/planner.py`` (2,345) * **Responsibilities:** device/placement/sharding planning and the encoded-data backend registry. * **Stateful globals:** the encoded-data backend registry (via ``register_encoded_data_backend``). * **Optional imports:** ``dask``, ``torch``. * **Serialization:** ``to_json`` / ``from_json`` (placement/plan round-trip — schema-visible). * **Extraction boundary:** the encoded-data backend registry and its backends are separable from the placement/calibration solver; a real seam, but touch it only with a distributed-path change. ``mixle/stats/compute/declarations.py`` (2,303) * **Responsibilities:** distribution declarations (parameter/statistic specs, exponential-family specs) and the Numba-lowering validation. * **Stateful globals:** ``_NUMBA_INFIX_OPS``, ``_NUMBA_FUNC_OPS``, ``_KNOWN_PARAMETER_CONSTRAINTS``, ``_SHARED_STACKED_PARAMETER_CONSTRAINTS`` (lowering tables). * **Optional imports:** none. * **Extraction boundary:** the Numba-lowering tables and their validation are separable from the spec dataclasses; split when the lowering rules next grow. ``mixle/stats/compute/pdist.py`` (2,068) * **Responsibilities:** the root contracts — the six-type ABCs, ``DensitySemantics``, and the error types (``ContractError``, ``EnumerationError``, ``KeyValidationError``). * **Stateful globals:** ``SS`` alias and ``_KEY_ATTRS``. * **Optional imports:** ``inspect`` and ``mixle`` submodules, deferred to avoid import cycles. * **Hot paths:** none of its own; it defines the signatures every hot path implements. * **Serialization:** ``from_json`` and the ``dist_to_encoder`` / ``seq_encode`` contract itself. * **Extraction boundary:** **do not split.** Nearly every module in the tree imports this one, so a split multiplies the import-cycle surface that ``doe_task_models_clean_import_test`` guards. The error classes could move if that test ever forces it, and nothing else should. ``mixle/stats/compute/fused_kernels.py`` (1,803) * **Responsibilities:** fused Numba kernels for mixture estimation over heterogeneous data, and the per-leaf builders that generate them. * **Stateful globals:** ``_BUILDERS`` (the leaf-builder registry) and ``_NEG_INF``. * **Optional imports:** Numba via the compute layer, ``scipy``, ``concurrent`` (parallel build), ``os``. * **Hot paths:** ``build_kernel``, ``seq_log_density``, ``seq_component_log_density``, and the ``_pair_kernels`` / ``_sequence_kernel`` / ``_optional_kernel`` generators. * **Serialization:** ``CompiledEncoding`` is the compiled-payload boundary, not a schema surface. * **Extraction boundary:** the ``_LeafBuilder`` subclasses are one clean seam per leaf family and the registry makes the split mechanical; the codegen core should stay whole. ``mixle/ppl/field.py`` (1,931) * **Responsibilities:** latent Gaussian fields observed through many proxies — kernels (RBF/Matern/great-circle/anisotropic), the field system, proxy likelihoods, and posterior readout. * **Stateful globals:** ``_SPARSE_SOLVE_DETECTORS`` (a detector registry). * **Optional imports:** ``torch`` and ``scipy``-backed sparse solves, both reached lazily. * **Hot paths:** kernel assembly and the sparse/dense posterior solve. * **Serialization:** field and proxy parameters round-trip through the owning system. * **Extraction boundary:** the ``FieldKernel`` hierarchy is fully separable from ``FieldSystem`` and the ``Proxy`` family; a genuine three-way seam, and the first place to split if this module grows. ``mixle/relations.py`` (1,825) * **Responsibilities:** relations over structured spaces enumerated by residual — shortest path, assignment, spanning tree, edit distance, Viterbi path, best-subset regression. * **Stateful globals:** none. * **Optional imports:** ``scipy`` (sparse/optimization routines), lazily. * **Hot paths:** each relation's enumeration loop; the residual ordering is the shared contract. * **Serialization:** ``Solution`` / ``Design`` carry the round-tripped state. * **Extraction boundary:** one module per relation is a clean, obvious split, held together only by the shared ``Relation`` base and its ordering guarantee. Defect-neutral; do it when one grows.