Package-wide simplification spec#
Status: in progress
Branch: worktree-simplify-package-cleanup
Progress#
Landed (each as its own commit):
Tier A — A1–A8, A11, A12, A13, plus one bonus finding (a
TestCompactOnlyVectorclass defined twice, the first shadowed and never executed).Tier B — B1 (
_dtype_sfx×31), B2/B3/B4 (the_jit_*chunking, mode and stride helpers).
Deliberately skipped, with reasons:
A9 (
_registered_platforms) — reported as always equal toset(self._kernels). True on the happy path only: the field records successful lowering registration, so if_register_fallback_loweringraises, the two diverge and a retry would re-attempt registration. Removing it changes error-path behaviour for the sake of one set. Not worth it.A10 (write-only FFI handler attributes) — entangled with C2, which rekeys the same cache. Should be done together, not separately.
Pallas compat shim — see “Adjudicated conflicts” below; needs JAX-version verification first.
dtype_suffixraising on unmapped dtypes — recommended by the reviewer, but it changes dispatch behaviour rather than preserving it. Documented and pinned by test instead; raising is a follow-up decision, not a cleanup.
Not started: B5–B17, all of Tier C, all of Tier D.
Verification at this point: full fast suite 1574 passed / 0 failed / 201 skipped; mypy 204 errors, down from the 208-error baseline (no regression).
Motivation#
A four-angle quality review (reuse, simplification, efficiency, altitude) of the
whole brainevent package (~53k lines of non-test source across ~60 modules)
produced 45 findings. This spec records them, tiers them by risk, and defines the
verification bar for landing them.
The review targeted quality only — reuse, simplification, efficiency, and altitude. It did not hunt for correctness bugs. A handful of probable bugs surfaced incidentally and are recorded in “Out of scope” below rather than fixed here.
Baseline (measured before any change)#
mypy(CI gate config): 208 errors in 23 files (75 source files checked). The gate is not currently clean, so the bar for this work is “no new errors”; reductions are a bonus.import brainevent: ~1.94 s cold; brainevent’s own module bodies 0.95–1.28 s.detect_cpp_toolchain(): 8.4 ms/call, uncached.Header glob + SHA-256 per compile-cache lookup: ~75 ms, paid even on a cache hit.
Re-lowering an identical CSR kernel: ~100–140 ms each time (full numba recompile).
Verification bar#
Per AGENTS.md:
Full test suite must pass (CI runs
pytest -m "", includingslowvariants).mypymust not regress past the 208-error baseline.Meaningful tests for edge cases and critical paths, not trivial line coverage.
Tests co-located as
foo_test.pybesidefoo.py(suffix style, never atests/directory, never atest_*.pyprefix).
Adjudicated conflicts#
Three findings were contested between reviewers and were resolved by direct inspection:
_dtype_sfx(31 copies). One reviewer declined to flag it, arguing each table maps to a different.cusymbol family. Verified false: all 31 bodies are byte-identical dtype→suffix maps (np.dtypevsjnp.dtypekeys resolve to the same objects). Only the base kernel name differs, and that stays at the call site._jit_uniform/binary.py:32already imports the table cross-module, proving it is shareable. Verdict: consolidate.cdiv. One reviewer called it dead code to delete; another wanted it reused. Verified: genuinely unreferenced outside_misc.py, while three_jit_*/csr.pymodules hand-roll its body as_n_chunks. Verdict: keep and adopt it.Pallas compat shim.
pallas_triton_params/pallas_mosaic_tpu_paramsare defined, exported in__all__, and used nowhere; the two real Pallas call sites passbackend=impl_backend. Whether wiring the shim up is correct depends on JAX-version behavior not yet verified. Verdict: defer pending verification; do not delete and do not blind-wire.
Tier A — mechanical, no behavior change#
# |
Site |
Change |
|---|---|---|
A1 |
|
Delete 9 never-called helpers (~443 lines): |
A2 |
package-wide |
Remove 18 |
A3 |
|
|
A4 |
|
|
A5 |
|
|
A6 |
|
|
A7 |
|
|
A8 |
|
Invert |
A9 |
|
|
A10 |
|
7 handler attributes are stored and never read; drop from the three |
A11 |
|
|
A12 |
|
Header scan runs 1576 regex attempts with no early exit; add |
A13 |
|
Stray |
Tier B — consolidate duplicates#
# |
Duplication |
Target |
|---|---|---|
B1 |
|
|
B2 |
|
|
B3 |
|
|
B4 |
|
|
B5 |
Operator-forwarding block ×4 subclasses (~950 lines) |
|
B6 |
|
|
B7 |
CSR |
|
B8 |
|
Make |
B9 |
XLA FFI callback body ×3 |
|
B10 |
|
One |
B11 |
|
Import |
B12 |
|
One |
B13 |
|
|
B14 |
|
One |
B15 |
|
Replace 7-way positional closure factory with module-level defs, mirroring |
B16 |
|
Two interchangeable workspace types (frozen dataclass vs namedtuple) that convert into each other mid-autodiff; keep one |
B17 |
|
Hoist 4 methods each onto the shared base using |
Tier C — efficiency#
# |
Site |
Change |
Measured cost today |
|---|---|---|---|
C1 |
|
Memoize |
~100–140 ms per re-lowering |
C2 |
|
Drop shapes from the FFI signature (they are never read; shape comes from |
One permanent FFI target + numba dispatcher per (kernel, shape), never evicted |
C3 |
|
Cache toolchain detection, invalidated by the existing |
8.4 ms/call |
C4 |
|
Cache header digests by |
~75 ms per lookup, paid on cache hits |
C5 |
|
Memoize |
per lowering |
C6 |
|
Defer |
creates a dir on |
C7 |
|
Lazy submodule imports via the existing PEP 562 |
~570 ms for a user who only touches |
Tier D — architectural#
These are design changes, not cleanups. Each needs its own validation and is sequenced last; any that prove too risky to land safely will be written up as follow-up specs rather than forced in.
# |
Finding |
Deeper fix |
|---|---|---|
D1 |
|
Implement once on |
D2 |
|
A |
D3 |
Unit split/reattach at ~70 entry points ( |
A decorator on the existing |
D4 |
191 hand-threaded |
|
D5 |
|
Backend resolved once at bind time as a static param, or the cuda_raw generator emits its own transpose |
D6 |
|
|
D7 |
|
|
D8 |
|
Resolve at bind time as static params, or setters clear caches |
D9 |
|
|
D10 |
|
Cheap |
Out of scope — probable correctness bugs#
Recorded, not fixed here. These need reproducing tests first per AGENTS.md rule 4.
clenint32/ceilnormalization applied in_jit_uniform/binary.py:741,1367but not in_jit_normal/binary.py:563,977or_jit_scalar/binary.py:704,1267._is_static_zero_probshort-circuit present in_jit_normal(3/3 entry points), partial in_jit_uniform(1/3), absent in_jit_scalar(0/3).JITCScalarR * JITCScalarRworks;JITCNormalR * JITCNormalRraises.Version guards below the supported floor (
jax < 0.4.38,< 0.4.34) are unreachable givenjax>=0.8.0;check_pallas_jax_versionguards(0,7,1)and can never raise. One of these is also a live mypy error (_compatible_import.py:55)._pallas_random.py(1,244 lines) is imported only by__init__.py; no_jit_*primitive registers a pallas backend.