You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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 AngleGroupTypedDict 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).