chore(deps): Bump the minor-and-patch group with 11 updates - #356
Merged
leehopper merged 2 commits intoSep 5, 2026
Merged
Conversation
Bumps Anthropic from 12.40.0 to 12.45.0 Bumps Aspire.Npgsql from 13.4.6 to 13.5.3 Bumps Marten from 9.25.0 to 9.31.2 Bumps Marten.EntityFrameworkCore from 9.25.0 to 9.31.2 Bumps OpenTelemetry from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Api from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Exporter.OpenTelemetryProtocol from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Extensions.Hosting from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Instrumentation.AspNetCore from 1.17.0 to 1.18.0 Bumps OpenTelemetry.Instrumentation.Http from 1.17.0 to 1.18.0 Bumps SonarAnalyzer.CSharp from 10.32.0.713 to 10.33.0.1635 --- updated-dependencies: - dependency-name: Anthropic dependency-version: 12.45.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Aspire.Npgsql dependency-version: 13.5.3 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Marten dependency-version: 9.31.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: Marten.EntityFrameworkCore dependency-version: 9.31.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Api dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Exporter.OpenTelemetryProtocol dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Extensions.Hosting dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Instrumentation.AspNetCore dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: OpenTelemetry.Instrumentation.Http dependency-version: 1.18.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch - dependency-name: SonarAnalyzer.CSharp dependency-version: 10.33.0.1635 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: minor-and-patch ... Signed-off-by: dependabot[bot] <support@github.com>
Dependency ReviewThe following issues were found:
License Issuesbackend/src/RunCoach.Api/RunCoach.Api.csproj
OpenSSF ScorecardScorecard details
Scanned Files
|
2 tasks
leehopper
enabled auto-merge (squash)
September 5, 2026 00:09
dependabot
Bot
deleted the
dependabot/nuget/backend/minor-and-patch-4d419ea6c5
branch
September 5, 2026 00:14
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.
Updated Anthropic from 12.40.0 to 12.45.0.
Updated Aspire.Npgsql from 13.4.6 to 13.5.3.
Release notes
Sourced from Aspire.Npgsql's releases.
13.5.3
What's New in Aspire 13.5.3
Patch release for Aspire 13.5 that fixes Dashboard Graph view crashes for resources with multi-path icons and restores missing public URLs for DevTunnel resources.
🐛 Fixes
📊 Dashboard Graph view could crash for Azure Blob resources — Resources such as those created with
AddBlobsuse icons containing multiple SVG paths, which caused an XML parsing exception and broke the dashboard circuit. The graph now combines multi-path icons correctly. Regression introduced in 13.5. Fixes #19489. (#19585, backport of #19579,@sebastienros)🌐 DevTunnel public URLs were missing from the Dashboard and MCP snapshots — DevTunnel port resources could report
RunningandHealthywhile showing no public URLs. Proxyless port allocation is now limited to compute and container resources, allowing DevTunnels to publish their actual public endpoints. Regression introduced in 13.5. Fixes #19496. (#19625, backport of #19590,@karolz-ms,@danegsta)🏷️ Housekeeping
Full Changelog: v13.5.2...v13.5.3
Full commit: b5f143315ffb6968ea939a9978797a5b20e4c688
13.5.2
What's New in Aspire 13.5.2
Patch release for Aspire 13.5 that removes an unused native helper binary from the Windows CLI archives so 13.5 servicing releases stay publishable to WinGet.
🐛 Fixes
hex1bpty.exe— The Windows CLI archives (aspire-cli-win-{x64,arm64}-*.zip) bundled Hex1b's out-of-process PTY host, which Aspire never executes (DCP owns every pseudo-terminal Aspire surfaces). Besides the wasted download, the extra unexplained executable stalled the WinGet publish, since every binary in the archive goes through executable and malware validation. A build-only MSBuild target now drops the file from the CLI publish output; Unix native assets are unaffected. Regression new in 13.5. ([#19557]([release/13.5] Exclude unused hex1bpty.exe from published CLI archives microsoft/aspire#19557), backport of #19554,@mitchdenny)🏷️ Housekeeping
Full Changelog: [v13.5.1...v13.5.2](microsoft/aspire@v13.5.1...v13.5.2)
Full commit: [a22cec24d76e764b3681977e314ab4a0aeed0240](microsoft/aspire@a22cec2)
13.5.1
What's New in Aspire 13.5.1
Patch release for Aspire 13.5 fixing a TypeScript/Java polyglot AppHost compatibility regression when running the 13.5 SDK under an older (13.4.x) CLI, plus a DCP update and release-pipeline housekeeping.
🐛 Fixes
🍎 Polyglot AppHosts could crash on startup on macOS — On macOS, polyglot (TypeScript/Python/Java/Go/Rust) AppHosts could crash during startup due to an interaction between how DCP's Go runtime forks detached processes and how .NET Native AOT installs its signal handlers. Updated DCP (Developer Control Plane) to 0.25.13 to resolve the crash. ([#19528]([release/13.5] [main] Update dependencies from microsoft/dcp microsoft/aspire#19528))
🔗 Polyglot AppHosts on the 13.5 SDK crashed under an older CLI with
MissingMethodException— A TypeScript or Java AppHost built with the 13.5 SDK failed to start when launched by an older (13.4.x) CLI, because the newer codegen calledAspire.TypeSystemmembers that don't exist in the CLI's older contract. Code generation now probes for these additive capabilities before using them, so older CLIs skip only the unsupported feature and startup succeeds. Regression introduced in 13.5 by #19365. Fixes #19503. ([#19524]([release/13.5] Preserve TypeSystem compatibility with older CLIs microsoft/aspire#19524), backport of #19506,@adamint)🏷️ Housekeeping
📦 Updated DCP (Developer Control Plane) to 0.25.13 ([#19528]([release/13.5] [main] Update dependencies from microsoft/dcp microsoft/aspire#19528))
🔧 Restored WinGet publication using .NET 9
wingetcreate([#19509]([release/13.5] fix(release): Restore WinGet publication with .NET 9 wingetcreate microsoft/aspire#19509))🧹 Removed the pipeline-scoped
Publish-Build-Assetsgroup from the release pipeline ([#19523]([release/13.5] Remove pipeline-scoped Publish-Build-Assets group microsoft/aspire#19523), [#19163](Remove Publish-Build-Assets variable group from release/13.5 microsoft/aspire#19163))🚀 Bumped branding to 13.5.1 ([#19531](Increment patch version from 0 to 1 microsoft/aspire#19531))
Full Changelog: [v13.5.0...v13.5.1](microsoft/aspire@v13.5.0...v13.5.1)
Full commit: [69db530a4816698cf1d5fa4557933e0ac4f127c6](microsoft/aspire@69db530)
13.5.0
Aspire 13.5.0
Aspire 13.5 is a developer-experience release focused on a richer, more interactive AppHost, closer C# and TypeScript parity, sharper tooling, more flexible deployment modeling, and a broad set of runtime-stability improvements.
Highlights
WithTerminal()API lets resources host REPLs, shells, TUIs, and other interactive programs directly in the dashboard, with an opt-inaspire terminalCLI command for attaching from your shell.ASPIREATS001experimental diagnostic and gain custom health checks, container file copying, HTTPS developer certificates, faster startup, and several reliability fixes that further close the gap with C#.aspire stop --force,aspire update --migrate,aspire doctor, docs search, signal handling, and stale-socket cleanup all improve day-to-day workflows.Aspire.Hosting.Dotnetpackage models .NET projects by path; Radius deployment arrives in preview; and Foundry Local, Redis modules, dev tunnels, Go debugging, and other integrations gain new capabilities.Notable changes include hosting context
ServiceProviderproperties being renamed toServices,PublishAsConnectionStringbecoming obsolete in favor ofAddConnectionString, removal ofaspire ps --resourcesand--include-hiddenin favor ofaspire describe, earlier proxyless endpoint port allocation, deprecation of the GitHub Models integration, removal of the dashboard AI Assistant, and opt-in rather than automatic dashboard launch from the VS Code extension.See the full list and migration guidance in the Aspire 13.5 breaking changes.
📖 Learn more
For complete details, examples, migration guidance, and everything new in this release, read What's new in Aspire 13.5.
Thank you to all the community contributors who helped make Aspire 13.5 possible! 💜
Full Changelog: v13.4.6...v13.5.0
Full commit: e076d8e427cb3afb528dbd605acd74c3aea69f94
Commits viewable in compare view.
Updated Marten from 9.25.0 to 9.31.2.
Release notes
Sourced from Marten's releases.
9.31.2
A diagnostics-only patch release. No behavioural change to the write path.
A failed batched write now reports the SQL that failed
When a batched write failed, Marten threw a
MartenCommandExceptionwhose message rendered an empty command text. Reported from the field on an async projection:The
$ $ $is the message template interpolating a command that was always null.ReadNpgsqlCommand()looks for anNpgsqlCommandinexception.Data, and on theExecuteBatchPagesAsyncpath there is no single command to put there —AutoClosingLifetimetransformed the exception with nothing recorded at all, andWrapAndThrow(NpgsqlBatch, ...)recorded the batch under a key that nothing ever read.The practical consequence: the offending SQL was unrecoverable from the exception and from the logs, for every async projection write. That is precisely the situation where hand-written SQL — a
QueueSqlCommand, a customIStorageOperation, a projection side effect — turns out to be malformed, and the one thing you need to see is the statement.MartenCommandExceptionnow recovers the SQL from three sources, in order:NpgsqlCommandit was handed;NpgsqlException.BatchCommand— Npgsql identifies the exact statement the server rejected when the failure came out of a batch execution;NpgsqlBatchrecorded on the exception.The recovered statement is also exposed on a new
MartenCommandException.CommandTextproperty, so it can be read programmatically rather than scraped out of the message.AutoClosingLifetimeexecutes its batches inline rather than throughhandleCommandException, so it now records its batch. The other three connection lifetimes already routed throughWrapAndThrow(NpgsqlBatch, ...)and only needed a reader for the key they were already writing.Two guardrails worth knowing about: a batch renders at most five statements, so a 500-operation projection page cannot turn one failure into an unreadable log entry, and the whole resolution is wrapped in a
catch— building a diagnostic must never replace the real failure.Also released as 8.38.1 on the 8.x line.
9.31.1
A single-fix patch release that moves Marten to JasperFx 2.61.0, picking up the source generator fix for JasperFx/jasperfx#733. Weasel stays on 9.29.0.
Self-aggregating snapshots silently skipped a constructor-based
CreateA self-aggregating snapshot may declare its Create handler as an event-shaped constructor,
public Foo(FooCreated e), instead of a namedstatic Create. That works on its own. Adding aShouldDeletemethod to the same aggregate switched the source generator to a different emitter — one that built its dispatch switch from named conventional methods only — so the constructor's event type got no case arm at all.Nothing failed loudly. The generated code compiled, the constructor never ran, and the next Apply-only event built the aggregate through
RuntimeHelpers.GetUninitializedObject, skipping every field initializer. The visible symptom was anApplyEventExceptionwrapping aNullReferenceExceptionout of anApplythat appended to a collection property:The quieter outcome, where no
Applyhappens to dereference anything, is a silently blank aggregate.Both documented workarounds — converting the constructor to a
static Create, or registering the delete throughDeleteEvent<T>()instead ofShouldDelete— become unnecessary on this release.The same omission was also in the generated
EventTypesproperty on every self-aggregating path, including the ones whose dispatch was already correct, so an aggregate with a constructorCreateand noShouldDeletegains its creating event in that list here too.Covered by
Bug_jasperfx_733_event_constructor_create_with_should_deleteacross inline, async and live aggregation, plus the delete arm itself. See #5322.9.31.0
Every fix in this release removes a silent wrong answer — not a crash, not an exception, but a plausible-looking result that was wrong with nothing to tell you so. A stream folded into partial aggregates. Paging that returned arbitrary pages. Monitoring that went dark rather than broken. A search reading a key that did not exist. An index that was never created.
Plus one genuinely new feature: weighted full text search with relevance ranking.
New: weighted full text indexes and
ts_rankorderingA full text index used to concatenate its members into one flat vector, so a match in a title was exactly as relevant as a match in a long description. Now it can be weighted, and ranked:
The rank resolves the same tsvector the
Whereclause matched on, read from the index definition. That is the load-bearing design constraint rather than an implementation detail: a rank computed over a different vector than the filter matched on returns rows in an order that looks plausible and means nothing — a far quieter failure than returning the wrong rows.Requires Weasel 9.29.0 (weasel#541), which made it possible to index an expression that is already a
tsvector. See the full text documentation for the costs worth knowing first — GIN cannot order, so this is a post-filter sort; and adding weights to an existing index drops and recreates it.Silent wrong answers, fixed
Async projections folded one stream into several partial aggregates (#5305, originally #4085). When a stream's events disagreed about
tenant_id, the daemon sliced it per tenant and applied the pieces over each other, so anApplysaw a document with every property at its default. Marten had setForceSingleTenancysince the original fix, butTenantedEventSlicerhonoured that flag on only one of its two overloads — and the async daemon reaches the other one. The flag was being set on precisely the path that could not read it. Fixed upstream in JasperFx 2.58.0.OrderByafter aGroupJoin/SelectManywas dropped from the SQL (#5311). Silently, and withSkip/Takeit was worse:OFFSETandLIMITwere emitted while the ordering was not, and unordered paging in PostgreSQL has no stable row order — so rows repeat across pages while others never appear.Whereon a bare-side selector andCountover a join were wrong in the same surface and are fixed too.A store with monitoring off dropped the monitoring columns another store had added (#5309). Two
DocumentStores over oneDatabaseSchemaNamethat disagreed aboutEnableExtendedProgressionTrackingkept stripping each other'smt_event_progressioncolumns — last writer wins, silent on both sides. A service beside a seeder or a reporting job is an ordinary arrangement, and neither was doing anything wrong. The shape of that table no longer depends on configuration at all.Full text search rewrote JSON keys, not just the column (#5314, thanks @mlh758). A member whose serialized name contained
dataproducedd.data ->> 'd.data'— a key that does not exist. Two quiet consequences: that member contributed nothing to the search, and the expression no longer matched the index, so the GIN index could not serve the query either.A second full text index over different members was silently discarded (#5315). Index names derive from the table rather than from the members, so two
FullTextIndex()calls collided by construction and the second was thrown away — never registered, never created, never searched. Ambiguity is now refused with an explanatory exception instead of resolved by declaration order.A DCB boundary aggregate failed far from its cause (JasperFx 2.60.0). An identity-less
[BoundaryAggregate]folded byEvolve(IEvent)got no evolver and no diagnostic, surfacing much later asFetchForWritingByTags<T>throwing "No source-generated dispatcher found" — naming neither the type nor the reason. Now it generates, and a[BoundaryAggregate]with nothing to fold events with is reported asJFXEVT007.A DCB tag version was captured after the events were read (#5300). Two batched statements do not share a
READ COMMITTEDsnapshot, so the version could reflect a concurrent append. Captured before the read now.Also in this release
projection-runCLI command arrives with JasperFx 2.60.0 and needs no Marten change — every host referencingJasperFx.Eventspicks it up. It replays one projection over a stream slice or DCB tag match and prints per-event before/after state, writing nothing.Bug_5268's concurrent index test no longer depends on how much unrelated transaction load happens to be in flight (#5308), so validating a dependency bump by running the whole suite at once is trustworthy again.BuildSlicernow agrees withFetchAsyncPlanabout global aggregates (#5307). Alignment rather than a fix — no reachable corruption depended on it, and the reasoning is written down at the call site so the question does not have to be reconstructed next time.Upgrade notes
OrderByFragment.Expressionschanged fromList<string>toList<ISqlFragment>. A public API break, deliberately taken: an ordering could not carry a parameter while the clause was a list of strings, which is why the older ngram ranking inlines its search term rather than binding it. Nothing outside Marten's own LINQ internals is likely to touch this type, but it is a compile break if you did.... (truncated)
9.30.0
Dependencies move to Weasel 9.27.0 and JasperFx 2.56.0.
Several fixes in this release share a failure mode worth calling out on its own: the write succeeded, the read disagreed, and nothing anywhere reported an error. Two of them ran undetected in production for weeks.
Patching
[JsonPropertyName](or[JsonProperty]under Newtonsoft) was patched at a path the serializer never reads. The patch reported success,LoadandQuerykept returning the old value, and the phantom node was erased by the next full save — so there was no durable evidence anything had gone wrong. Patch paths now resolve through the same member machinery the LINQ provider uses, soWhere(x => x.Name == v)andPatch(...).Set(x => x.Name, v)agree about where a member lives by construction. The predicate overloads had the same gap and are fixed with it..Duplicate()column now refreshes that column in more of the cases that need it: an aliased member, a patch on a parent of the duplicated member, and the destinations of the patching API's ownDuplicateandRenameoperations. Left unfixed, the document and the index that exists to search it disagreed —Loadreturned the new value whileQueryfiltered on the same member returned nothing.DCB
Events.BuildHStoreTagIndexConcurrentlybuilds the hstore tag index without holdingACCESS EXCLUSIVEonmt_eventsfor the duration. On an ordinary event table that isCREATE INDEX CONCURRENTLY; underEvents.UseTenantPartitionedEvents, where PostgreSQL refusesCONCURRENTLYon a partitioned parent outright, Marten emits the per-partition sequence it does accept. Opt-in, because a concurrent build cannot run inside a transaction and so changes whatdb-patchanddb-dumpwrite out. The out-of-band route from 9.29.0 (Events.IgnoreIndex(EventGraph.HStoreTagIndexName)) still works and is still supported.mt_dcb_tag_versionrows, invalidating a concurrent session that did have something to append. A boundary is now only enforced when the save actually appends. #5280 covers the repeated-fetch half: each row is asserted exactly once, oldest capture wins.Events.TagWith<T>(...)states once how an event is tagged and applies it wherever the event is built — ordinary appends,StartStream, aggregate handlers and bulk inserts alike — closing the gaps tag inference leaves open.Events.TagEventsBy(...)hands over a translator an application already owns instead of restating it one registration at a time.LINQ
x.EnumArray.Contains(variable)resolved to theMemoryExtensions.Containscomparer overload rather thanEnumerable.Contains, because enums do not implementIEquatable<T>; withImplicitUsingson, most applications hit this by default.HashSet<TEnum>in aContainsfilter now projects to something Npgsql can bind.MatchesJsonPath(sql, params object[])overload threw for every call. It now works for any argument type, maps null ontoDBNull, and reports a placeholder/parameter count mismatch with a message naming both counts instead of anIndexOutOfRangeExceptionfrom inside the LINQ provider. Worth knowing:^is the placeholder character for that overload and is also a regex anchor, so it lands inside JSONPath literals by accident.Async daemon
min(seq_id)over a join, and PostgreSQL only rewritesMINinto an ordered index scan when the aggregate's input is a single relation. The probe therefore scanned every remaining row in the partition, on the one code path that exists precisely because the store is too large for the normal query to finish.Pausedshard after a rollout.9.29.0
Data-loss and silent-failure fixes across the event append path, DCB tagging, and schema naming. Two of these lose or drop data with no error at all, so they are worth reading even if the rest is not relevant to you.
Data loss
A retried commit could lose its events entirely (#5262).
QuickAppendEventsOperationBasereleased its pooled parameter buffers inPostprocessAsync, but the resilience pipeline can re-execute the sameNpgsqlBatch— and a releasedPooledListreportsCount = 0, which Npgsql binds as the array length. The retry sent empty event arrays,mt_quick_append_eventswrote nothing and raised nothing, andSaveChangesAsyncreturned success having committed the documents without the events. The rentals now belong to the unit of work.Commits are no longer retried when the outcome is unknown (#5262). A commit carries event appends and is not idempotent, so replaying one that already committed server-side appends the events twice.
SaveChangesAsyncnow runs through a separate write pipeline that retries only when the previous attempt is known to have left nothing behind — a transient error PostgreSQL reported itself, or a failure Marten's own post-processing raised and rolled back. A command timeout or a dropped connection now surfaces instead of being replayed.This is deliberately not
NpgsqlException.IsTransient, whose definition is built for idempotent work and includes the whole connection-exception class.ConfigurePollyandExtendPollynow govern reads only;ConfigureWritePolly/ExtendWritePollyare new for the commit path. See Resiliency Policies.Only the first DCB tag of a given type was stored (#5265).
mt_quick_append_eventscarries one array per tag type, parallel to the events, so it had exactly one slot per (event, tag type). An event legitimately carrying two tags of one type lost the rest — and a lost tag is not an error to a DCB query, it is simply absent from the answer. The surplus is now written as ordinary tag rows. InDcbStorageMode.HStore, which cannot represent the case at all, this now throws rather than dropping silently.Schema
Long primary key constraint names could collide outright. A document table's PK constraint was left on Weasel's
pkey_{table}_{columns}default, which passes 63 characters for a document type of no great length oncetenant_idjoins the key. PostgreSQL truncates rather than rejecting, and the constraint's backing index is schema-scoped, so two document types whose names agree for long enough failed with42P07 relation "pkey_..." already exists. Also fixed for the natural key table (#5271). No-op for any schema that was not already being truncated.Multi-database tenancy ignored
Command Timeouton shard connection strings (#5269).StoreOptions.CommandTimeoutwas only ever raised fromStoreOptions.Connection(...), which multi-database setups never call — so every command ran at the 5 second default no matter what the shards said. The database being used now has a say. An explicitly set store-wide value still wins.FetchForWritingByTagsbroke later full-schema operations (#5264).EventGraph.Build<TDoc>()resolved the id type throughMappingFor, which registers aDocumentMappingas a side effect — so a pure[BoundaryAggregate], which has no identity by design, became a document type with noIdMember.ResetAllData,ApplyAllConfiguredChangesToDatabaseAsyncand thedb-patch/db-applycommands then threw.Projections and DCB
EF Core projection rebuilds corrupted the DbContext (#5266). The daemon applies a range's slices through a 10-wide block, all sharing one storage instance — and the EF Core storage wraps a single non-thread-safe
DbContext. Requires JasperFx 2.53.0, which lets a storage declare it cannot take concurrent slices.Bulk-imported events now carry DCB tags in hstore mode (#5267), thanks to @erdtsieck. Previously every bulk-imported event landed untagged, so a store whose history arrived by migration had a consistency boundary that silently excluded most of it.
The DCB hstore tag index can be built out of band (#5268). Enabling hstore mode on an existing store built a GIN index under
ACCESS EXCLUSIVE— a write outage rather than a migration, with no way around it under per-tenant partitioning.EventGraph.HStoreTagIndexNamecan now be passed toEvents.IgnoreIndexso an operator builds it themselves; see the DCB docs for the procedure.A lost append race under conjoined tenancy surfaced as a raw
PostgresException(#5270). The exception transform recognised the stream-version guard index by an enumerated list of names, and partitioning gives each partition a differently-named child index. It was missing three, not one — including on the single-tenant configuration #3520 was meant to have fixed. Now matched by shape.Also
FetchForWritingaggregate cache now really does skip the snapshot load —IdentityMapDocumentStorage.LoadManyAsyncwas issuing an empty-id query even when the item map had satisfied everything (#5258, #5259, #5260).Thanks
@erdtsieck for #5262, #5264, #5267, #5268 and #5269 — several of these were forensic reports of silent data loss with the mechanism worked out, which is how they got fixed this quickly. @Noblix for the #5265 repro.
9.28.0
Full Changelog: JasperFx/marten@V9.27.0...V9.28.0
What's Changed
Full Changelog: JasperFx/marten@V9.27.0...V9.28.0
9.27.0
Adopts JasperFx 2.51.0 and the four capabilities it promotes into the shared Critter Stack contracts. One of them is a genuinely new Marten feature; the other three close gaps where Marten had the capability but not under the shared spelling.
Aggregate snapshot caching for
FetchForWriting(#5251)An opt-in, node-local cache of aggregate snapshots that lets
FetchForWritingskip loading the stored snapshot and read only the events after it — effectively an identity map for aggregates with a lifetime longer than a session. Off for every aggregate type; enabled per type, because the win is proportional to how often one stream is fetched for writing:The cached snapshot is only ever a baseline. The stream version and every event after the cached version are still read on every call, and the optimistic concurrency assertion on append is untouched — so a stale entry costs a larger delta query, never a wrong aggregate and never a suppressed
EventStreamUnexpectedMaxEventIdException. That is what makes a deliberately incoherent, node-local cache the right shape here, and why there is no distributed-cache option: a distributed cache would reintroduce exactly the round trip this exists to remove.Both the Async and Inline lifecycles are supported, and they genuinely differ. An Inline snapshot is written in the same transaction as the events, so it is always exactly at the stream head — a hit needs an exact version match, and the entry is written back only after a successful commit, because the inline projection mutates the very instance
FetchForWritinghanded out.IAggregateWriteCacheand friends live inJasperFx.Events.Fetching, so one cache implementation serves Marten, Polecat and Fisher alike. No new package lands on core Marten: the default is backed byJasperFx.Core's existing LRU rather thanMicrosoft.Extensions.Caching.Memory.Docs: Optimizing Performance → Caching Aggregate Snapshots for FetchForWriting.
IDocumentSessionOperations.PendingStreams(#5250)Store-agnostic code can now read the
StreamActions a session has queued but not yet committed — for a listener or a pre-commit hook deciding something from the events the session is about to write — without naming a store.Eventsaccessor. Marten'sPendingChanges.Streams()returnsIList<StreamAction>, andIList<T>is not assignable toIReadOnlyList<T>, so the member bound to the interface's throwing default with no compile error anywhere. It now carries an explicit implementation, pinned byPendingStreamActionsCompliance.In Marten this is the same collection as
IDocumentSession.PendingChanges.Streams(), handed back as a live view rather than a copy.BinaryEventAttribute— one lookup instead of two (#5248)Marten.Events.BinaryEventAttributenow derives from the promotedJasperFx.Events.BinaryEventAttribute, which 2.51.0 unsealed for exactly this.EventGraph.ResolveBinarySerializerFordrops back to a single attribute lookup. Entirely non-breaking — existing[BinaryEvent]usages compile and resolve unchanged.Compliance (#5249)
DocumentComplianceConfig.StreamIdentityis now replayed by Marten's document compliance fixture rather than inferred, and two new shared suites are enrolled:PendingStreamActionsComplianceandAggregateWriteCacheCompliance(wave 10).Upgrading
No breaking changes and no migration. Everything new here is opt-in.
Full changelog: JasperFx/marten@V9.26.0...V9.27.0
9.26.0
Consumes JasperFx 2.50.0, which promoted two things into the shared contracts. Both changes here are additive — existing code compiles and behaves identically.
Reach the event store from a store-agnostic session (jasperfx#669)
JasperFx.Events.Documentsgained anEventsaccessor on its session contracts, so a consumer that opens its own session throughIDocumentSessionFactorycan now reach the event store without naming Marten:IDocumentReadOperationsIQueryEventStore EventsIDocumentSessionOperationsIEventStoreOperations EventsMarten implements both. This does not affect handlers taking a chain parameter — Wolverine already fills those. It matters for the two shapes where you decide when a session exists: a background or timer publisher that opens a session and appends, and a deliberate second read session opened alongside a chain's writing session.
Eventsproperty of its own event-store type does not satisfy the contract member — it binds to a default that throws, and the build still succeeds with zero errors. Marten's ownIQuerySession.EventsreturnsMarten.Events.IQueryEventStore, a subtype, which is exactly this case; both tiers needed an explicit implementation. The shared compliance suite is what catches it.IEventBinarySerializerpromoted toJasperFx.EventsBinary event serialization (#4515) was Marten-specific, so a consumer compiling one body of source against several Critter Stack stores needed a separate identical serializer per store. The two-method interface and
[BinaryEvent]now live inJasperFx.Events, and one serializer serves every store.Non-breaking, in both directions:
Marten.Events.IEventBinarySerializerstill exists and now derives from the core interface, so existing implementations keep compiling and also satisfy the core type.EventGraph.UseBinarySerializer<T>,DefaultBinarySerializer,IEventStoreOptionsandEventMapping.BinarySerializerwidened to accept the core interface, so a store-agnostic serializer can be registered.[BinaryEvent]attributes are honored.Fixed: binary serializer registration was order-dependent
EventMappingresolved its binary serializer in its constructor, andAddEventType<T>()builds mappings eagerly. So this threw"no IEventBinarySerializer was registered"out of what reads as a plain type registration:while the same two lines in the opposite order worked. Resolution is lazy now, deferring the failure to first use — which is what the documentation always described. The guard is
volatile, because it is read from the append path on many threads and a torn read would route a binary event down the JSON path silently rather than throwing.Also
DocumentSessionEventsComplianceandBinaryEventSerializationCompliance.events/binary-serialization.md,documents/sessions.md.Full changelog: JasperFx/marten@9.25.0...9.26.0
Commits viewable in compare view.
Updated Marten.EntityFrameworkCore from 9.25.0 to 9.31.2.
Release notes
Sourced from Marten.EntityFrameworkCore's releases.
9.31.2
A diagnostics-only patch release. No behavioural change to the write path.
A failed batched write now reports the SQL that failed
When a batched write failed, Marten threw a
MartenCommandExceptionwhose message rendered an empty command text. Reported from the field on an async projection:The
$ $ $is the message template interpolating a command that was always null.ReadNpgsqlCommand()looks for anNpgsqlCommandinexception.Data, and on theExecuteBatchPagesAsyncpath there is no single command to put there —AutoClosingLifetimetransformed the exception with nothing recorded at all, andWrapAndThrow(NpgsqlBatch, ...)recorded the batch under a key that nothing ever read.The practical consequence: the offending SQL was unrecoverable from the exception and from the logs, for every async projection write. That is precisely the situation where hand-written SQL — a
QueueSqlCommand, a customIStorageOperation, a projection side effect — turns out to be malformed, and the one thing you need to see is the statement.MartenCommandExceptionnow recovers the SQL from three sources, in order:NpgsqlCommandit was handed;NpgsqlException.BatchCommand— Npgsql identifies the exact statement the server rejected when the failure came out of a batch execution;NpgsqlBatchrecorded on the exception.The recovered statement is also exposed on a new
MartenCommandException.CommandTextproperty, so it can be read programmatically rather than scraped out of the message.AutoClosingLifetimeexecutes its batches inline rather than throughhandleCommandException, so it now records its batch. The other three connection lifetimes already routed throughWrapAndThrow(NpgsqlBatch, ...)and only needed a reader for the key they were already writing.Two guardrails worth knowing about: a batch renders at most five statements, so a 500-operation projection page cannot turn one failure into an unreadable log entry, and the whole resolution is wrapped in a
catch— building a diagnostic must never replace the real failure.Also released as 8.38.1 on the 8.x line.
9.31.1
A single-fix patch release that moves Marten to JasperFx 2.61.0, picking up the source generator fix for JasperFx/jasperfx#733. Weasel stays on 9.29.0.
Self-aggregating snapshots silently skipped a constructor-based
CreateA self-aggregating snapshot may declare its Create handler as an event-shaped constructor,
public Foo(FooCreated e), instead of a namedstatic Create. That works on its own. Adding aShouldDeletemethod to the same aggregate switched the source generator to a different emitter — one that built its dispatch switch from named conventional methods only — so the constructor's event type got no case arm at all.Nothing failed loudly. The generated code compiled, the constructor never ran, and the next Apply-only event built the aggregate through
RuntimeHelpers.GetUninitializedObject, skipping every field initializer. The visible symptom was anApplyEventExceptionwrapping aNullReferenceExceptionout of anApplythat appended to a collection property:The quieter outcome, where no
Applyhappens to dereference anything, is a silently blank aggregate.Both documented workarounds — converting the constructor to a
static Create, or registering the delete throughDeleteEvent<T>()instead ofShouldDelete— become unnecessary on this release.The same omission was also in the generated
EventTypesproperty on every self-aggregating path, including the ones whose dispatch was already correct, so an aggregate with a constructorCreateand noShouldDeletegains its creating event in that list here too.Covered by
Bug_jasperfx_733_event_constructor_create_with_should_deleteacross inline, async and live aggregation, plus the delete arm itself. See #5322.9.31.0
Every fix in this release removes a silent wrong answer — not a crash, not an exception, but a plausible-looking result that was wrong with nothing to tell you so. A stream folded into partial aggregates. Paging that returned arbitrary pages. Monitoring that went dark rather than broken. A search reading a key that did not exist. An index that was never created.
Plus one genuinely new feature: weighted full text search with relevance ranking.
New: weighted full text indexes and
ts_rankorderingA full text index used to concatenate its members into one flat vector, so a match in a title was exactly as relevant as a match in a long description. Now it can be weighted, and ranked:
The rank resolves the same tsvector the
Whereclause matched on, read from the index definition. That is the load-bearing design constraint rather than an implementation detail: a rank computed over a different vector than the filter matched on returns rows in an order that looks plausible and means nothing — a far quieter failure than returning the wrong rows.Requires Weasel 9.29.0 (weasel#541), which made it possible to index an expression that is already a
tsvector. See the full text documentation for the costs worth knowing first — GIN cannot order, so this is a post-filter sort; and adding weights to an existing index drops and recreates it.Silent wrong answers, fixed
Async projections folded one stream into several partial aggregates (#5305, originally #4085). When a stream's events disagreed about
tenant_id, the daemon sliced it per tenant and applied the pieces over each other, so anApplysaw a document with every property at its default. Marten had setForceSingleTenancysince the original fix, butTenantedEventSlicerhonoured that flag on only one of its two overloads — and the async daemon reaches the other one. The flag was being set on precisely the path that could not read it. Fixed upstream in JasperFx 2.58.0.OrderByafter aGroupJoin/SelectManywas dropped from the SQL (#5311). Silently, and withSkip/Takeit was worse:OFFSETandLIMITwere emitted while the ordering was not, and unordered paging in PostgreSQL has no stable row order — so rows repeat across pages while others never appear.Whereon a bare-side selector andCountover a join were wrong in the same surface and are fixed too.A store with monitoring off dropped the monitoring columns another store had added (#5309). Two
DocumentStores over oneDatabaseSchemaNamethat disagreed aboutEnableExtendedProgressionTrackingkept stripping each other'smt_event_progressioncolumns — last writer wins, silent on both sides. A service beside a seeder or a reporting job is an ordinary arrangement, and neither was doing anything wrong. The shape of that table no longer depends on configuration at all.Full text search rewrote JSON keys, not just the column (#5314, thanks @mlh758). A member whose serialized name contained
dataproducedd.data ->> 'd.data'— a key that does not exist. Two quiet consequences: that member contributed nothing to the search, and the expression no longer matched the index, so the GIN index could not serve the query either.A second full text index over different members was silently discarded (#5315). Index names derive from the table rather than from the members, so two
FullTextIndex()calls collided by construction and the second was thrown away — never registered, never created, never searched. Ambiguity is now refused with an explanatory exception instead of resolved by declaration order.A DCB boundary aggregate failed far from its cause (JasperFx 2.60.0). An identity-less
[BoundaryAggregate]folded byEvolve(IEvent)got no evolver and no diagnostic, surfacing much later asFetchForWritingByTags<T>throwing "No source-generated dispatcher found" — naming neither the type nor the reason. Now it generates, and a[BoundaryAggregate]with nothing to fold events with is reported asJFXEVT007.A DCB tag version was captured after the events were read (#5300). Two batched statements do not share a
READ COMMITTEDsnapshot, so the version could reflect a concurrent append. Captured before the read now.Also in this release
projection-runCLI command arrives with JasperFx 2.60.0 and needs no Marten change — every host referencingJasperFx.Eventspicks it up. It replays one projection over a stream slice or DCB tag match and prints per-event before/after state, writing nothing.Bug_5268's concurrent index test no longer depends on how much unrelated transaction load happens to be in flight (#5308), so validating a dependency bump by running the whole suite at once is trustworthy again.BuildSlicernow agrees withFetchAsyncPlanabout global aggregates (#5307). Alignment rather than a fix — no reachable corruption depended on it, and the reasoning is written down at the call site so the question does not have to be reconstructed next time.Upgrade notes
OrderByFragment.Expressionschanged fromList<string>toList<ISqlFragment>. A public API break, deliberately taken: an ordering could not carry a parameter while the clause was a list of strings, which is why the older ngram ranking inlines its search term rather than binding it. Nothing outside Marten's own LINQ internals is likely to touch this type, but it is a compile break if you did.... (truncated)
9.30.0
Dependencies move to Weasel 9.27.0 and JasperFx 2.56.0.
Several fixes in this release share a failure mode worth calling out on its own: the write succeeded, the read disagreed, and nothing anywhere reported an error. Two of them ran undetected in production for weeks.
Patching
[JsonPropertyName](or[JsonProperty]under Newtonsoft) was patched at a path the serializer never reads. The patch reported success,LoadandQuerykept returning the old value, and the phantom node was erased by the next full save — so there was no durable evidence anything had gone wrong. Patch paths now resolve through the same member machinery the LINQ provider uses, soWhere(x => x.Name == v)andPatch(...).Set(x => x.Name, v)agree about where a member lives by construction. The predicate overloads had the same gap and are fixed with it..Duplicate()column now refreshes that column in more of the cases that need it: an aliased member, a patch on a parent of the duplicated member, and the destinations of the patching API's ownDuplicateandRenameoperations. Left unfixed, the document and the index that exists to search it disagreed —Loadreturned the new value whileQueryfiltered on the same member returned nothing.DCB
Events.BuildHStoreTagIndexConcurrentlybuilds the hstore tag index without holdingACCESS EXCLUSIVEonmt_eventsfor the duration. On an ordinary event table that isCREATE INDEX CONCURRENTLY; underEvents.UseTenantPartitionedEvents, where PostgreSQL refusesCONCURRENTLYon a partitioned parent outright, Marten emits the per-partition sequence it does accept. Opt-in, because a concurrent build cannot run inside a transaction and so changes whatdb-patchanddb-dumpwrite out. The out-of-band route from 9.29.0 (Events.IgnoreIndex(EventGraph.HStoreTagIndexName)) still works and is still supported.mt_dcb_tag_versionrows, invalidating a concurrent session that did have something to append. A boundary is now only enforced when the save actually appends. #5280 covers the repeated-fetch half: each row is asserted exactly once, oldest capture wins.Events.TagWith<T>(...)states once how an event is tagged and applies it wherever the event is built — ordinary appends,StartStream, aggregate handlers and bulk inserts alike — closing the gaps tag inference leaves open.Events.TagEventsBy(...)hands over a translator an application already owns instead of restating it one registration at a time.LINQ
x.EnumArray.Contains(variable)resolved to theMemoryExtensions.Containscomparer overload rather thanEnumerable.Contains, because enums do not implementIEquatable<T>; withImplicitUsingson, most applications hit this by default.HashSet<TEnum>in aContainsfilter now projects to something Npgsql can bind.MatchesJsonPath(sql, params object[])overload threw for every call. It now works for any argument type, maps null ontoDBNull, and reports a placeholder/parameter count mismatch with a message naming both counts instead of anIndexOutOfRangeExceptionfrom inside the LINQ provider. Worth knowing:^is the placeholder character for that overload and is also a regex anchor, so it lands inside JSONPath literals by accident.Async daemon
min(seq_id)over a join, and PostgreSQL only rewritesMINinto an ordered index scan when the aggregate's input is a single relation. The probe therefore scanned every remaining row in the partition, on the one code path that exists precisely because the store is too large for the normal query to finish.Pausedshard after a rollout.9.29.0
Data-loss and silent-failure fixes across the event append path, DCB tagging, and schema naming. Two of these lose or drop data with no error at all, so they are worth reading even if the rest is not relevant to you.
Data loss
A retried commit could lose its events entirely (#5262).
QuickAppendEventsOperationBasereleased its pooled parameter buffers inPostprocessAsync, but the resilience pipeline can re-execute the sameNpgsqlBatch— and a releasedPooledListreportsCount = 0, which Npgsql binds as the array length. The retry sent empty event arrays,mt_quick_append_eventswrote nothing and raised nothing, andSaveChangesAsyncreturned success having committed the documents without the events. The rentals now belong to the unit of work.Commits are no longer retried when the outcome is unknown (#5262). A commit carries event appends and is not idempotent, so replaying one that already committed server-side appends the events twice.
SaveChangesAsyncnow runs through a separate write pipeline that retries only when the previous attempt is known to have left nothing behind — a transient error PostgreSQL reported itself, or a failure Marten's own post-processing raised and rolled back. A command timeout or a dropped connection now surfaces instead of being replayed.This is deliberately not
NpgsqlException.IsTransient, whose definition is built for idempotent work and includes the whole connection-exception class.ConfigurePollyandExtendPollynow govern reads only;ConfigureWritePolly/ExtendWritePollyare new for the commit path. See Resiliency Policies.Only the first DCB tag of a given type was stored (#5265).
mt_quick_append_eventscarries one array per tag type, parallel to the events, so it had exactly one slot per (event, tag type). An event legitimately carrying two tags of one type lost the rest — and a lost tag is not an error to a DCB query, it is simply absent from the answer. The surplus is now written as ordinary tag rows. InDcbStorageMode.HStore, which cannot represent the case at all, this now throws rather than dropping silently.Schema
Long primary key constraint names could collide outright. A document table's PK constraint was left on Weasel's
pkey_{table}_{columns}default, which passes 63 characters for a document type of no great length oncetenant_idjoins the key. PostgreSQL truncates rather than rejecting, and the constraint's backing index is schema-scoped, so two document types whose names agree for long enough failed with42P07 relation "pkey_..." already exists. Also fixed for the natural key table (#5271). No-op for any schema that was not already being truncated.Multi-database tenancy ignored
Command Timeouton shard connection strings (#5269).StoreOptions.CommandTimeoutwas only ever raised fromStoreOptions.Connection(...), which multi-database setups never call — so every command ran at the 5 second default no matter what the shards said. The database being used now has a say. An explicitly set store-wide value still wins.FetchForWritingByTagsbroke later full-schema operations (#5264).EventGraph.Build<TDoc>()resolved the id type throughMappingFor, which registers aDocumentMappingas a side effect — so a pure[BoundaryAggregate], which has no identity by design, became a document type with noIdMember.ResetAllData,ApplyAllConfiguredChangesToDatabaseAsyncand thedb-patch/db-applycommands then threw.Projections and DCB
EF Core projection rebuilds corrupted the DbContext (#5266). The daemon applies a range's slices through a 10-wide block, all sharing one storage instance — and the EF Core storage wraps a single non-thread-safe
DbContext. Requires JasperFx 2.53.0, which lets a storage declare it cannot take concurrent slices.Bulk-imported events now carry DCB tags in hstore mode (#5267), thanks to @erdtsieck. Previously every bulk-imported event landed untagged, so a store whose history arrived by migration had a consistency boundary that silently excluded most of it.
The DCB hstore tag index can be built out of band (#5268). Enabling hstore mode on an existing store built a GIN index under
ACCESS EXCLUSIVE— a write outage rather than a migration, with no way around it under per-tenant partitioning.EventGraph.HStoreTagIndexNamecan now be passed toEvents.IgnoreIndexso an operator builds it themselves; see the DCB docs for the procedure.A lost append race under conjoined tenancy surfaced as a raw
PostgresException(#5270). The exception transform recognised the stream-version guard index by an enumerated list of names, and partitioning gives each partition a differently-named child index. It was missing three, not one — including on the single-tenant configuration #3520 was meant to have fixed. Now matched by shape.Also
FetchForWritingaggregate cache now really does skip the snapshot load —IdentityMapDocumentStorage.LoadManyAsyncwas issuing an empty-id query even when the item map had satisfied everything (#5258, #5259, #5260).Thanks
@erdtsieck for #5262, #5264, #5267, #5268 and #5269 — several of these were forensic reports of silent data loss with the mechanism worked out, which is how they got fixed this quickly. @Noblix for the #5265 repro.
9.28.0
Full Changelog: JasperFx/marten@V9.27.0...V9.28.0
What's Changed
Full Changelog: JasperFx/marten@V9.27.0...V9.28.0
9.27.0
Adopts JasperFx 2.51.0 and the four capabilities it promotes into the shared Critter Stack contracts. One of them is a genuinely new Marten feature; the other three close gaps where Marten had the capability but not under the shared spelling.
Aggregate snapshot caching for
FetchForWriting(#5251)An opt-in, node-local cache of aggregate snapshots that lets
FetchForWritingskip loading the stored snapshot and read only the events after it — effectively an identity map for aggregates with a lifetime longer than a session. Off for every aggregate type; enabled per type, because the win is proportional to how often one stream is fetched for writing:The cached snapshot is only ever a baseline. The stream version and every event after the cached version are still read on every call, and the optimistic concurrency assertion on append is untouched — so a stale entry costs a larger delta query, never a wrong aggregate and never a suppressed
EventStreamUnexpectedMaxEventIdException. That is what makes a deliberately incoherent, node-local cache the right shape here, and why there is no distributed-cache option: a distributed cache would reintroduce exactly the round trip this exists to remove.Both the Async and Inline lifecycles are supported, and they genuinely differ. An Inline snapshot is written in the same transaction as the events, so it is always exactly at the stream head — a hit needs an exact version match, and the entry is written back only *after...
_Description has bee...
Description has been truncated