Skip to content

JasperFx 2.69.2

Choose a tag to compare

@jeremydmiller jeremydmiller released this 13 Sep 14:50
· 116 commits to main since this release

Two fixes and a documentation correction.

#832 — generated statement order moved between runs

Thanks to @AllainPL for the diagnosis, the provenance and a deterministic repro.

MethodFrameArranger.compileFrames step 3 enumerated DependencyGatherer.Dependencies, an ImHashMap keyed by Frame. Frame does not override GetHashCode, so that walk followed identity hash codes and differed between two arrangements of the same logical method — and step 4's topological sort preserves the relative order of independent frames, so the emitted body carried the variation. #196 fixed exactly this for DependencyGatherer.Variables, which is why constructor parameters and fields have been stable and the statements inside the method were not.

Measured on a real application with committed generated code, running codegen write twice in the same environment: 15 of 60 files differed at 1.24.1, 6 of 60 still differed at 1.31.0 (the first release carrying #196). What was left moving is statement order. This also closes out JasperFx/wolverine#3059, which reported the same drift as a macOS-vs-Linux difference and guessed at the cause without a repro.

The fix walks frames and indexes the cache rather than enumerating the cache. The cache's keys are exactly the frames passed in — DependencyGatherer's constructor fills one entry per frame and nothing adds a key before step 3 — so the set gathered is unchanged and only the order becomes deterministic.

⚠️ Expect a one-time diff. If you have generated code committed, regenerating on 2.69.2 may reorder statements within a method once as they settle into a stable order. That is this fix landing, not a semantic change. Subsequent regenerations are byte-identical — which is the point: a drift check in CI, a code review, or a reproducible build can now tell a real change from hash-order noise.

#831 — a stale claim on SupportsMultipleDatabases

The remarks said "Fisher is legitimately false — one file, one database." Fisher has had database-per-tenant since fisher#47 and runtime tenants since fisher#58, and both arms of MultiDatabaseExplorerCompliance are green there. Replaced with the store-neutral condition, plus the part that makes it matter: a Fisher tenant is a file, so this is the one suite in the set whose precondition is nearly free there and expensive on the other two — the opposite of what the old sentence implied.

Docs

WaitForNonStaleProjectionDataAsync's contract is now stated on the fixture seam: wait on every configured shard, not every shard that has reported. An implementation that gates on the rows it finds is satisfied by a store where one projection reached the head and another never ran — the wait returns and the next read sees a document that was never written. polecat#602 shipped that defect.