Skip to content

v0.1.6

Choose a tag to compare

@imewei imewei released this 31 Aug 00:09
· 51 commits to main since this release

[0.1.6] - 2026-08-30

Fixed

  • Negative-dominant D_offset now detected in physics validators. The
    D_offset/D0 overfitting checks only compared ratio > 0.5, missing the
    symmetric case where a large-magnitude negative offset dominates D0
    (e.g. D_offset_ref/D0_ref = -0.503 in a real C045 two_component fit,
    implying a negative diffusion coefficient at early times). Both checks now
    compare abs(ratio) > 0.5 (#75).
  • Resolved mypy hard-gate failures on main (CI run 33300386957): explicit
    type annotations for union-typed locals in fallback_chain.py,
    recovery.py, and validation.py, plus a new AngleGroup TypedDict in
    chunking.py replacing an overly-loose dict[str, Any] (#73).
  • Duplicate HeterodyneModel class name. Two unrelated classes shared
    the name — core/heterodyne_model.py's PhysicsModelBase adapter and
    core/heterodyne_model_stateful.py's public stateful model — so
    from xpcsjax.core.heterodyne_model import HeterodyneModel and
    from xpcsjax.core import HeterodyneModel silently returned different
    classes. Renamed the adapter to HeterodynePhysicsAdapter across every
    real call site; the public xpcsjax.core.HeterodyneModel export is
    unaffected (#71).
  • Stratified-LS (>=1M point) diagonal-exclusion mask compared indices
    into two independently-built np.unique() arrays instead of the actual
    t1/t2 values, wrongly zeroing real off-diagonal points and keeping
    true diagonal ones (#71).
  • Hybrid-streaming per_angle_mode="constant" fallback index
    misalignment.
    In the quantile-estimation-failure fallback, L3's
    regularization group indices and L4's gradient-collapse-monitor watched
    indices were resolved via the literal per_angle_mode_actual string
    instead of the real 2-param [contrast_mean, offset_mean, *physical]
    layout the fallback actually uses, watching the scaling head as if it
    were physics (#71).
  • coerce_finite_float no longer silently coerces a stray YAML boolean
    (e.g. a typo'd max: true) to 1.0/0.0 at the shared bounds/values
    validation boundary (#71).
  • Degenerate 1-frame Siegert-ceiling check no longer reads the excluded
    tau=0 diagonal spike.
    The matrix.shape[1] <= 1 fallback branch in
    data/filtering_utils.py and data/validation.py read diagonal[0]
    into the check instead of skipping it, reintroducing the anti-pattern the
    surrounding code otherwise avoids (#71).
  • 19 correctness gaps closed in the NLSQ fitting workflow and 6 more across
    config/core/viz, found via independent step-by-step audits that traced the
    NLSQ workflow and docs/diagrams/architecture.md against the real code.

Removed

  • ~7800 lines of confirmed-dead code removed repo-wide (ponytail-audit).

Documentation

  • Config examples across the documentation now match the shipped YAML
    templates exactly — bounds format, key nesting, and the heterodyne
    physics/scaling parameter layout — instead of several invented shapes
    that a reader could not actually load (#70).
  • Theory prose terminology and notation cleaned up: dropped the "diffusion
    integral" label for D(t1,t2) (referred to by symbol only, alongside
    J(t)), and aligned Sphinx theory notation with the README (#69, #70).

Dependencies

  • nlsq bumped 0.7.1 → 0.7.4 and evosax bumped 0.2.0 → 0.3.1 in
    uv.lock and the conda recipe (conda-recipe/xpcsjax/meta.yaml); host
    setuptools floor raised to >=77 to match evosax 0.3.1's build
    requirement (#74).