Compliance wave 5 part 1: explorer, archiving and FetchLatest suites (2.39.4) - #633
Merged
Conversation
Three more shared suites, 19 tests, taking the library from 105 to 124. - EventStoreExplorerCompliance (6) - GetRecentStreamsAsync, GetStreamMetadataAsync and TryCreateUsage. Worth pinning cross-store because these are throwing default-interface methods with an out-of-repo consumer (CritterWatch), so a half-built implementation fails nothing at compile time. - StreamArchivingCompliance (6) - ArchiveStream and its consequences: the archived flag on stream state, idempotence, neighbour isolation, and that the recorded version survives archiving. Physical partition movement stays product-specific. - FetchLatestCompliance (7) - FetchLatest/ProjectLatest, including agreement with a live fold and with a store where the aggregate is registered nowhere. Three capability gates added to the fixture, all default true: SupportsExplorerSurface, SupportsUsageEventTypeDescriptors and SupportsStreamMetadataTags. The latter two exist because adoption found two real Polecat defects (polecat#411, polecat#412) - an empty Events collection on the usage descriptor, and a null Tags dictionary where StreamMetadata declares it non-nullable. The assertions stay; the gates are temporary and tracked. Marten 124/124, Polecat 123 passed + 1 gated skip. Note on FetchLatest and pending events: two drafts asserted that FetchLatest sees uncommitted appends - first through a bare Append, then through the FetchForWriting handle - and both were wrong about the contract rather than finding a bug. Neither product promises it, and Marten's own test for that path saves first. The suite now pins the documented sequence (fetch for writing, append, save, read back on the same session), which still catches the real risk there: a stale cached aggregate. Refs JasperFx/marten#5138, #5140, #5146, #5118 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde
polecat#411 (empty usage.Events) and polecat#412 (null StreamMetadata.Tags) are fixed, so neither store needs SupportsUsageEventTypeDescriptors or SupportsStreamMetadataTags. Removing them rather than leaving unused capability gates around: a gate nobody needs is an invitation to soften an assertion later. SupportsExplorerSurface stays -- the explorer methods are throwing default interface methods, so a minimal store may legitimately not implement them at all. Polecat 124/124 with no gates.
jeremydmiller
added a commit
to JasperFx/polecat
that referenced
this pull request
Aug 4, 2026
…412) Both found by a new cross-store compliance suite (EventStoreExplorerCompliance, JasperFx/jasperfx#633) rather than by Polecat's own tests -- which is the point of the shared suite. #411: EventStoreUsage carries the event registry twice, as Events (List<EventDescriptor>) and RegisteredEventTypes (List<EventTypeDescriptor>). Marten fills both; Polecat filled only RegisteredEventTypes, so usage.Events came back empty. This descriptor is read out of repo by CritterWatch, where an empty Events list reads as "this store has no event types configured" rather than "this store describes them under a different key". Now populated from the same AllKnownEventTypes() loop that already fed RegisteredEventTypes. #412: GetStreamMetadataAsync returned Tags: null!, but StreamMetadata.Tags is declared as a non-nullable IReadOnlyDictionary<string, string>. "No tags" is spelled with an empty dictionary; null forces every consumer that trusts the declaration into a NullReferenceException instead of an empty loop. The `null!` silenced the compiler's warning rather than answering it. Now a shared static empty dictionary, so there is no per-stream allocation. Deliberately product-only: the compliance enrollment that proves these lands separately, once the JasperFx release carrying the suite is out. Closes #411 Closes #412 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde
jeremydmiller
added a commit
to JasperFx/polecat
that referenced
this pull request
Aug 4, 2026
…412) (#413) Both found by a new cross-store compliance suite (EventStoreExplorerCompliance, JasperFx/jasperfx#633) rather than by Polecat's own tests -- which is the point of the shared suite. #411: EventStoreUsage carries the event registry twice, as Events (List<EventDescriptor>) and RegisteredEventTypes (List<EventTypeDescriptor>). Marten fills both; Polecat filled only RegisteredEventTypes, so usage.Events came back empty. This descriptor is read out of repo by CritterWatch, where an empty Events list reads as "this store has no event types configured" rather than "this store describes them under a different key". Now populated from the same AllKnownEventTypes() loop that already fed RegisteredEventTypes. #412: GetStreamMetadataAsync returned Tags: null!, but StreamMetadata.Tags is declared as a non-nullable IReadOnlyDictionary<string, string>. "No tags" is spelled with an empty dictionary; null forces every consumer that trusts the declaration into a NullReferenceException instead of an empty loop. The `null!` silenced the compiler's warning rather than answering it. Now a shared static empty dictionary, so there is no per-stream allocation. Deliberately product-only: the compliance enrollment that proves these lands separately, once the JasperFx release carrying the suite is out. Closes #411 Closes #412 Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 4, 2026
jeremydmiller
added a commit
to JasperFx/marten
that referenced
this pull request
Aug 4, 2026
Enrolls the three shared suites that shipped in 2.39.4 (JasperFx/jasperfx#633): fetch_latest_compliance (7), stream_archiving_compliance (6) and event_store_explorer_compliance (6). Marten's compliance coverage goes from 105 to 124 tests with zero capability gates. No Marten code changes -- every entry point the three suites exercise was already on the shared JasperFx surfaces, so this is a version bump plus one file of empty subclasses. Verified on net9.0 against the published packages: 124/124 compliance. Closes #5138 Closes #5140 Closes #5146 Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
jeremydmiller
added a commit
to JasperFx/polecat
that referenced
this pull request
Aug 4, 2026
Enrolls the three shared suites that shipped in 2.39.4 (JasperFx/jasperfx#633): fetch_latest_compliance (7), stream_archiving_compliance (6) and event_store_explorer_compliance (6). Polecat's compliance coverage goes from 105 to 124 tests with zero capability gates. No gates are needed because #413 already fixed what they would have covered: the explorer suite found an empty usage.Events collection (#411) and a null StreamMetadata.Tags (#412) while it was being written, and those landed separately so they did not have to wait on a JasperFx release. The two temporary gates were removed from the compliance library before it shipped, so these assertions run unmodified here. The version jump also picks up 2.39.2 and 2.39.3, which had not been adopted yet. Verified on net9.0 against the published packages: 124/124 compliance. Claude-Session: https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Compliance wave 5, part 1 — three more suites from the portable-today group of the backlog (marten#5118). 19 tests, library 105 → 124.
EventStoreExplorerComplianceGetRecentStreamsAsync,GetStreamMetadataAsync,TryCreateUsageStreamArchivingComplianceArchiveStreamand its consequencesFetchLatestComplianceFetchLatest/ProjectLatestVerified against working copies of both stores: Marten 124/124, Polecat 124/124 plus its full suite at 1722/0/3. Zero capability gates on either store.
What adoption found — two real Polecat defects, both now fixed
This is the payoff argument for the shared suite, so it's worth being concrete: neither of these was caught by either product's own tests.
EventStoreUsagecarries the event registry twice, asEventsandRegisteredEventTypes. Marten fills both; Polecat filled only the latter, sousage.Eventscame back empty. This descriptor is read out of repo by CritterWatch, where an emptyEventslist reads as "this store has no event types configured" rather than "this store describes them under a different key".GetStreamMetadataAsyncreturnedTags: null!, butStreamMetadata.Tagsis declared as a non-nullableIReadOnlyDictionary<string, string>. "No tags" is spelled with an empty dictionary; null forces every consumer that trusts the declaration into aNullReferenceException. Thenull!had silenced the compiler's warning rather than answering it.Both are fixed in polecat#413, so the assertions here stand unmodified and the two capability gates I added while diagnosing them have been removed again. An unused gate is an invitation to soften an assertion later, so the second commit takes them back out.
SupportsExplorerSurfacestays — the explorer methods are throwing default-interface methods, so a genuinely minimal store may not implement them at all.A note on FetchLatest and pending events
Two drafts of
fetch_latest_after_fetch_for_writing_and_save_is_not_staleasserted thatFetchLatestsees uncommitted appends — first through a bareAppend, then through theFetchForWritinghandle. Both failed, and both times the claim was wrong rather than the store: neither product documents that behaviour, and Marten's own test for this path saves before reading back.The suite now pins the documented sequence (fetch for writing → append → save → read back on the same session), which still guards the real risk in that path: a stale cached aggregate surviving the save. The dead end is recorded in the test's
<remarks>so it isn't re-litigated.Scope notes
StreamArchivingCompliancedeliberately stops at behaviour. Physical partition movement — Marten's archived event partition and Polecat's equivalent — is storage layout and stays in each product's own tests. Where the two stores could legitimately differ (whether archived events are excluded from a default stream read or returned flagged), the suite asserts the invariant they must share: an archived stream's events must never come back claiming to be live.JasperFxVersion2.39.3 → 2.39.4, in this PR, per the--skip-duplicatepublish trap.🤖 Generated with Claude Code
https://claude.ai/code/session_01VpDCvJcBDZerieJB4JEHde