0.9.1
A single fix — #102, found from one intermittent CI failure while 0.9.0 was being released.
Non-stale waits on the shards the store registers
WaitForNonStaleProjectionDataAsync — and QueryForNonStaleData behind it — decided it was done from the rows in fi_event_progression rather than from the shards the store registers. A shard that has not started has no row and therefore no sequence to be behind, so it was invisible: with two async projections the wait returned the moment the first one reached the head.
What that costs is the whole point of the call. An application asking for non-stale data was told its data was current while a projection had never run, and read empty documents that look like real answers.
The same rule was broken the other way round, which fixing it surfaced: with events present and no progression rows at all, a store with no async projections waited out its timeout on every call.
Registered shards are now the authority in both directions:
| registered shard, no row | stale |
| registered shard, behind | stale (unchanged) |
| no async projections registered | returns immediately |
| row for a shard nothing registers | ignored — an orphan from a de-registered projection never advances again |
⚠️ Behaviour change
A wait with a registered async projection and no daemon running now waits out its timeout and throws TimeoutException, where it used to return early. That is the honest answer — nothing is going to advance that shard — but it will surface anywhere a test waits for non-stale data without starting a daemon. The message now names the shards that have recorded nothing at all, so "never started" reads differently from "still catching up".
Why it took an intermittent to find
It presented once, as rebuild_and_catch_up_compliance.rebuilding_one_projection_leaves_another_alone on a loaded two-core CI runner — green on the other target framework in the same run and 25/25 locally in isolation. The window is the gap between one shard's first commit and the next shard's.
The regression test is seeded rather than raced, and it needs two registered shards: with no rows at all the old rule waited too, so a store where nothing has run cannot tell the two rules apart. Mutation-checked — reverting to the row-derived rule fails it and the two "returns immediately" facts.
Compatibility
No API changes. Requires JasperFx 2.51.0; Weasel stays at 9.24.0. Everything in 0.9.0 — the aggregate write cache, PendingStreams, and the 2.51.0 bump — is unchanged.