Release 0.2.1 — Daily CI repair, API reference refresh#
Status: implemented
Branch: worktree-release-0.2.1
1. Motivation#
Three independent problems were bundled into the 0.2.1 patch release:
Daily CI Tests failed on the pinned-JAX matrix legs (runs
31234230842,31290069801) while the unpinned leg passed.The Daily CI matrix did not cover JAX 0.10.x, the newest supported minor, so the release matrix silently under-tested the version most users install.
docs/reference/apis/had drifted from the public API. Symbols removed in 0.2.0 were still documented, and 44 public exports had no reference page.
2. Daily CI failure — root cause#
Failing test: brainevent/_op/main_test.py::test_f17_kernel_generator_failure_is_wrapped_with_alternatives.
The test asserted that a kernel-generator exception is preserved as the direct
__cause__ of the raised KernelCompilationError:
assert isinstance(excinfo.value.__cause__, RuntimeError)
JAX’s jax._src.traceback_util.api_boundary rewrites the cause chain of any
exception that crosses an API boundary:
jax_error.__cause__ = e.__cause__ # original cause is pushed one level down
e.__cause__ = jax_error # synthetic frame becomes the direct cause
The synthetic frame is UnfilteredStackTrace (JAX 0.10) or
JaxStackTraceBeforeTransformation (JAX 0.8/0.9). Whether it is inserted depends
on the active jax_traceback_filtering mode, whose default differs across JAX
minors — hence the failure on pinned 0.8.0/0.9.0 and the pass on the unpinned leg.
The library behaviour was correct throughout; only the assertion was too strict.
Fix#
Landed in a66dcee: assert against the whole __cause__ chain rather than the
first link.
def _exception_chain_contains(exc, expected_type, expected_text: str) -> bool:
while exc is not None:
if isinstance(exc, expected_type) and expected_text in str(exc):
return True
exc = getattr(exc, '__cause__', None)
return False
This is invariant to how many synthetic frames JAX splices in, so it holds for every supported JAX version.
Verification#
Clean virtualenvs pinned to each matrix version, full suite (pytest brainevent/ -m ""):
JAX |
Result |
|---|---|
0.8.0 |
pass |
0.9.0 |
pass |
0.10.2 (unpinned) |
pass |
3. Daily CI matrix#
jax-version extended from [ "0.8.0", "0.9.0", "" ] to
[ "0.8.0", "0.9.0", "0.10.0", "" ], so every supported minor is pinned
explicitly and the empty entry continues to track the newest release.
4. API reference refresh#
docs/reference/apis/*.rst was audited by comparing every autosummary entry
against brainevent.__all__ and brainevent.config.__all__.
4.1 Stale entries removed (41)#
File |
Removed |
|---|---|
|
|
|
|
|
|
The lfsr* and get_numba_* helpers live in the private brainevent._numba_random
module and are not re-exported, so currentmodule:: brainevent could never resolve
them; they are kernel-generation internals and are intentionally not part of the
public reference.
4.2 Public exports added (44)#
File |
Added |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4.3 Structural changes#
Exceptions consolidated.
operator.rstpreviously documented four exception classes whileerrors.rstdocumented six others, leaving ten undocumented. All twenty now live inerrors.rst, grouped by subtree and preceded by the inheritance tree;operator.rstcross-references it.Deprecated aliases dropped.
FixedPreNumConn/FixedPostNumConnemit aDeprecationWarningon attribute access; the reference now documents the replacementsFixedNumPerPre/FixedNumPerPost.
4.4 Prose pages#
The narrative docs cited the same retired symbols, and two of their snippets no longer ran at all:
Page |
Problem |
Fix |
|---|---|---|
|
|
rewritten against the real constructors and executed end to end |
|
same non-existent |
rewritten with explicit |
|
cites |
replaced by |
|
deprecated |
|
|
43 uses of the deprecated aliases across prose, code and recorded output |
renamed; notebook JSON re-validated |
The alias mapping is crossed, so the rename is not a search-and-replace of the
obvious pairs: FixedPostNumConn → FixedNumPerPre (a fixed number of post
-synaptic connections per pre-synaptic neuron) and FixedPreNumConn →
FixedNumPerPost. Both directions were taken from brainevent/_deprecation.py
rather than inferred from the names.
4.5 Regression guard#
docs/reference/apis/api_coverage_test.py re-runs the audit as a test: every
autosummary entry must resolve on its currentmodule, and every name in
brainevent.__all__ must appear in exactly one reference page. Deprecated
aliases and the config submodule handle are the only allowed exemptions.
5. Edge cases and test coverage#
Edge case |
Handling |
|---|---|
JAX splices 0, 1 or N synthetic frames into |
chain walk terminates on |
Cause chain cycles |
not reachable — Python forbids self-referential |
A new public export added without a doc entry |
|
A doc entry outliving its symbol |
|
Deprecated alias re-added to a reference page |
allowed-exemption list is explicit, so it must be edited deliberately |
|
test resolves |