diff --git a/src/Polecat/DocumentStore.EventStore.cs b/src/Polecat/DocumentStore.EventStore.cs index 9997dc2..a30d979 100644 --- a/src/Polecat/DocumentStore.EventStore.cs +++ b/src/Polecat/DocumentStore.EventStore.cs @@ -315,8 +315,18 @@ Task IEventStore.CompactStreamAsync(string streamKey, CancellationToken token) // Event-type registry — populates the explorer's "known event types" // panel without forcing operators to crack open assembly metadata. + // + // #411: BOTH collections have to be filled. EventStoreUsage carries the event registry + // twice — Events (List) and RegisteredEventTypes + // (List) — and Marten populates both. Filling only + // RegisteredEventTypes left usage.Events empty, which reads to a consumer as "this store + // has no event types configured" rather than "this store describes them elsewhere". foreach (var registered in Options.EventGraph.AllKnownEventTypes()) { + usage.Events.Add(new EventDescriptor( + registered.EventTypeName, + TypeDescriptor.For(registered.EventType))); + usage.RegisteredEventTypes.Add(new EventTypeDescriptor( EventType: TypeDescriptor.For(registered.EventType), Alias: registered.EventTypeName, diff --git a/src/Polecat/Events/Internal/PcStreamsRowReader.cs b/src/Polecat/Events/Internal/PcStreamsRowReader.cs index 5662fc2..af45960 100644 --- a/src/Polecat/Events/Internal/PcStreamsRowReader.cs +++ b/src/Polecat/Events/Internal/PcStreamsRowReader.cs @@ -111,6 +111,14 @@ internal static StreamSummary ReadStreamSummary(DbDataReader reader, string defa /// column is used as the fallback, mirroring the pre-consolidation /// behavior in DocumentStore.GetStreamMetadataAsync. /// + /// + /// Shared empty tag set for . Polecat does not persist + /// DCB stream tags yet, so every row reports the same immutable empty dictionary rather + /// than allocating one per stream. + /// + private static readonly IReadOnlyDictionary EmptyTags = + new Dictionary(); + internal static StreamMetadata ReadStreamMetadata( DbDataReader reader, string defaultTenantId, @@ -134,7 +142,12 @@ internal static StreamMetadata ReadStreamMetadata( LastSnapshotVersion: null, IsArchived: isArchived, TenantId: tenantId, - Tags: null!); + // #412: an empty dictionary, never null. StreamMetadata.Tags is declared as a + // non-nullable IReadOnlyDictionary, so "this stream has no tags" is spelled with an + // empty collection -- a null forces every consumer that trusts the declaration into a + // NullReferenceException instead of an empty loop. The `null!` that used to be here + // silenced the compiler's warning rather than answering it. + Tags: EmptyTags); } private static string StreamIdToString(object value) => value switch