src/xorl/ops/
_vendored/ # third-party, lint-excluded centrally, never hand-edited
quack/ # moved from ops/quack (VENDORED.md pattern generalized)
flashqla/ # moved from ops/linear_attention/flashqla
exact/ # the serving-parity byte-contract programs, one naming convention
sampling_transforms.py # from ops/exact_sampling_transforms.py
rope_class_b.py, canonical_moe_leaf.py, canonical_moe_cast.py,
one_round_swiglu.py # from fused_silu_and_mul.py (exact half)
block_fp8_native.py, kernel_config_pin.py, bi_gemm_configs.py
batch_invariant/ # batch_invariant_ops.py split by concern:
lm_head.py, norms.py, trunk_linear.py, router_gemm.py
loss/ # CE/logprob KERNELS only (per_token_ce, compiled_cross_entropy,
# bi_fused_lm_head, sampling_transform_ce, fused_linear_logprob,
# vocab_parallel_*)
moe/ # + ep_kernels/ merged in (deepep sort/scatter are MoE dispatch)
linear_attention/ # pure kernels only (chunk scan, conv, gating)
ssm/ # pure kernels only
quantize/
src/xorl/objectives/ # RL losses out of ops/loss: policy_loss, grpo_loss, cispo_loss,
# importance_sampling_loss, opd_loss, opd_streaming_kl,
# reducers, loss_output, causallm_loss (the LossOutput-level API)
src/xorl/models/layers/ # layer classes out of ops: GatedDeltaNet (+ fused_norm_gate
# modules), Mamba2Mixer
src/xorl/models/transformers/glm5/kernels/ # from ops/glm5_kernels
src/xorl/models/transformers/deepseek_v4/kernels/ # from ops/dsv4
Problem
src/xorl/opsis the largest package in the tree (225 files, ~72k lines) and has become a grab-bag of four different kinds of code sharing one namespace:ops/quack/(59 files, ~28k lines) andops/linear_attention/flashqla/are vendored,ops/bi_families_v2.pyis vendored byte-identical into the serving engine and sha256-gated — together they are more than half ofops/by volume, yet nothing structural distinguishes them from code we own. This has practical costs: a tree-wideruff --fixrecently "fixed" 45 vendored quack files, and every reader burns time discovering what is editable.batch_invariant_ops.py(2,188 lines),bi_families_v2.py,bi_gemm_configs.py,exact_sampling_transforms.py,rope_class_b.py,canonical_moe_leaf.py,canonical_moe_cast.py,fused_silu_and_mul.py,kernel_config_pin.py,block_fp8_native.py— thebi_/exact_/canonical_/class_bprefixes all mean the same thing ("byte-pinned serving-parity program"), andbatch_invariant_ops.pyalone mixes lm-head, norm, trunk-linear, and router contracts in one module.ops/contains raw kernels (glm5_kernels/,dsv4/), autograd ops, fullnn.Modulelayers (GatedDeltaNetunderops/linear_attention/layers/,Mamba2Mixerunderops/ssm/), and complete RL objective functions (policy_loss,grpo_loss,cispo_loss,importance_sampling_loss,opd_*inops/loss/). The objectives are consumed by the trainer/runner, not by models — they are not "ops".ops/glm5_kernels/andops/dsv4/duplicate the family split that already exists undermodels/transformers/{glm5,deepseek_v4}/.Reference points
fusions/(flat, one fused op per file) is separate fromtransformer/(layers) which is separate frommodels/; third-party integration lives inextensions/; parallelism-specific ops intensor_parallel/. Kernels ≠ layers ≠ models, and each is one directory.backends/megatron_utilsboundary and serving isbackends/sglang_utils. XoRL is unusual in owning both the orchestration and a kernel library, which is whyops/ballooned. The transferable lesson is the explicit boundary: our serving-parity programs are effectively a vendored contract surface with SGLang and deserve the same clear edge that slime gives its backends.Target layout
What deliberately does NOT move
ops/bi_families_v2.py— vendored byte-identical into SGLang and sha256-gated (tests/ops/test_bi_golden_gates.py, pre-commit formatting carve-out). It stays at its exact path;ops/exact/re-exports it. Moving it means re-pinning the golden gates on both sides for zero benefit.Phasing (sequenced against in-flight work)
Each phase is one PR, branched from
main, landed before the next starts. Phases avoid files owned by open PRs until those merge.flashqla/VENDORED.mdpattern toquack/andbi_families_v2.py(banner comment), centralize the vendored lint/format excludes in one pre-commit/ruff block, and addops/README.mddocumenting the taxonomy above. Zero import churn.quack/andflashqla/underops/_vendored/with re-export stubs; update thepyproject.tomlvendoring note and any sync tooling paths. Purely mechanical; biggest visual win (~30k lines out of the first-party namespace).ops/loss/): createxorl/objectives/, move the RL objective modules, leave the CE/logprob kernel stack inops/loss/. Consumers: trainer, model_runner, PP loss factory.ops/exact/gathering +batch_invariant_ops.pysplit (coordinate with Consolidate the exact and generic scoring paths; implement top-k/top-p/min-p on the generic path #71 point 4, which touches the same surface): one naming convention for the serving-parity family;bi_families_v2.pystays put and is re-exported.ops/glm5_kernels/andops/dsv4/intomodels/transformers/{glm5,deepseek_v4}/kernels/; layer classes (GatedDeltaNet,Mamba2Mixer, fused norm-gate modules) intomodels/layers/; kernels stay inops/.ep_kernels/intomoe/, retire grab-bagutils.pynames, delete empty shells (ops/group_gemmis already removed by Remove dead modules, measurement artifacts, and stale references #77).Migration mechanics
git mv, then a stub module at the old path doingfrom xorl.ops._vendored.quack import * # moved; remove after <date>so out-of-tree configs, notebooks, and the path-pinning source-inspection tests keep working during the window.tests/distributedfile-shard claims inpr-test-cpu.ymlare updated in the same PR (enforced bytests/test_cpu_test_shards.py).Acceptance criteria
ops/contains only kernels and autograd ops: nonn.Modulelayer classes, no RL objectives.batch_invariant_ops.pyno longer exists as a 2,100-line multi-concern module.Adjacent debt (observed, explicitly out of scope here)
server/runner/model_runner.pyis ~8.5k lines and the real monolith of the repo; splitting it deserves its own issue.fp8_training/,qarl/,qlora/,lora/) could arguably group under one namespace, but they are small, self-contained, and not worth the churn now.sim/(~21k lines) is self-contained and fine where it is.Refs: #65 (churn cost), #71 (point 4 shares files with Phase 3), #74, #77 (sequencing). Structure comparisons: Megatron-core
fusions/transformer/extensions; slime/miles backend boundaries.