Skip to content

Publish gates: swallow only time-empty results, pass channel-empty through - #180

Merged
cboulay merged 2 commits into
devfrom
publish-gate-time-axis
Jul 22, 2026
Merged

Publish gates: swallow only time-empty results, pass channel-empty through#180
cboulay merged 2 commits into
devfrom
publish-gate-time-axis

Conversation

@cboulay

@cboulay cboulay commented Jul 21, 2026

Copy link
Copy Markdown
Member

Summary

Units that suppress empty publishes — Downsample, BinnedAggregate, Window — or use emptiness to terminate a drain loop — ResampleUnit, ResampleConcat — keyed on data.size == 0. That conflates two cases:

  1. No new samples along the time-like axis (chunk closed no bin / no complete window / resampler has nothing ready) — correctly suppressed.
  2. Empty along some other axis — e.g. an upstream Slicer with on_empty="warn" (Slicer: add on_empty setting — no-match selections warn and emit empty by default #177) sliced away every channel while time samples remain — which should flow downstream so consumers that align or merge multiple sources keep the stream's cadence.

Changes

  • New is_empty_along(message, dims) in ezmsg.sigproc.util.message: true iff any named dim is present in the message with zero length (absent dims ignored).
  • Downsample.on_signal / BinnedAggregate.on_signal: swallow only when settings.axis (default "time") is 0-length.
  • Window.on_signal: swallow only when the win newaxis (or, in pass-through mode, the windowed axis) is 0-length.
  • ResampleUnit publisher / ResampleConcat._drain: terminate the drain only on an empty resample axis. This one was the sharpest edge: with a 0-channel stream, every chunk had prod(shape) == 0, so the drain would break before publishing and silently drop real time chunks indefinitely.

Not changed (already correct)

The remaining size == 0 sites (filter.py, butterworthzerophase.py, fbcca.py, rollingscaler.py, filterbank.py) are compute guards that pass the message through unchanged rather than swallowing it — passthrough is already right for a channel-empty message. ResampleConcatProcessor.__next__'s shape[0] == 0 check was already time-axis-based.

Testing

  • New tests/unit/test_empty_gate.py (5 tests): the helper; Downsample, BinnedAggregate, and Window driven directly through on_signal, asserting channel-empty results publish and time-empty results are swallowed; and a stub-processor test proving ResampleConcat._drain no longer terminates on a 0-feature chunk.
  • Full unit suite passes on the branch (3609 passed, 5 skipped), plus the window and downsample integration systems (9 passed).

cboulay added 2 commits July 21, 2026 19:15
…rough

Units that suppress empty publishes (Downsample, BinnedAggregate, Window) or
use emptiness to terminate a drain loop (ResampleUnit, ResampleConcat) keyed
on data.size == 0, which conflates two cases: no new samples along the
time-like axis (correctly suppressed) vs. all channels/features sliced away
upstream while time samples remain (e.g. Slicer with on_empty='warn'). The
latter should flow downstream so consumers that align or merge multiple
sources keep the stream's cadence.

Add is_empty_along(msg, dims) to util.message and re-key each gate on the
unit's time-like axis (settings.axis; for Window also the 'win' newaxis).
ResampleProcessor.__next__ signals 'not initialized' with a dimensionless
null template (dims=[''], key='null') that has no time axis at all, so the
is_empty_along gate published it -- and kept draining -- flooding downstream
with null messages until the first reference arrived
(test_resample_system_reference_driven caught this).

Add has_samples_along(msg, dim) -- dim present AND nonzero -- and use it in
both drain loops: anything that is not a well-formed chunk along the resample
axis means 'nothing ready'. Channel-empty chunks still publish.
@cboulay
cboulay merged commit 6bab483 into dev Jul 22, 2026
14 checks passed
@cboulay
cboulay deleted the publish-gate-time-axis branch July 22, 2026 00:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant