GH-4152/4147/4146: adopt JasperFx 2.56 provenance and add event-model --url - #4153
Merged
jeremydmiller merged 1 commit intoAug 26, 2026
Merged
Conversation
… --url Bumps the JasperFx pins to 2.56.0 and takes the three things that unlocks. GH-4152 / GH-4147 — provenance instead of registration order. WolverineEventModelSource and HttpEventModelSource both read their roles off compiled chains, so both now declare EventModelProvenance.Derived. That lets the services.Insert(0, ...) in UseWolverine() and MapWolverineEndpoints() become plain AddSingleton calls: the insert was load-bearing behaviour that nothing in the registration explained, and the class doc had to spell it out. Both are gone. Note the deliberate inversion this buys: a source that OBSERVES a running system now outranks a derived one. Production truth beating what the code says it should do is the point of the ladder, not a regression. GH-4146 — event-model --url. PUTs the assembled descriptor to a monitor instead of, or as well as, writing the file, so the design-time loop is one command: dotnet watch run -- event-model --url http://localhost:5525 JsonFlag's default moves from "event-model.json" to null so --url on its own does not also litter the application directory; with neither flag the command still writes event-model.json exactly as before. Wolverine takes no reference on the monitor -- it is an HTTP PUT to whatever URL is named. A monitor that is down fails with a one-line message and a non-zero exit rather than a stack trace, because under dotnet watch a console that has not been started yet is the ordinary case and must not look like a crash. Deliberately NOT a --watch flag: this process already has the assembly loaded, so an internal loop would re-serialize the same chains forever. Only a fresh process picks up recompiled handlers. On testing the provenance change honestly. The existing GH-3988 fixture registers an overlay BEFORE UseWolverine() and asserts the overlay may only fill gaps, which looks like the regression guard for this change. It is not: it passes with or without the Derived stamp. The public overlay API (EventModelSliceBuilder) can only express TriggeredBy / InDomain / LinksToSpecification / Hotspot -- annotations, none of which are factual roles -- so an overlay cannot collide with a derived role and that fixture never exercises the ladder at all. The new event_model_provenance_ladder_4147 tests use custom IEventModelDefinitionSource stubs that do claim a colliding role, and they test GH-4147's acceptance criteria as written: an observed source overrides a derived role, a declared one cannot. Verified red -- with the stamp removed, the declared rival registered first unions into the derived role (["MerelyDeclared", "PaymentRecorded"]) instead of losing to it. One existing test asserted the Wolverine source was registered FIRST. That pinned the mechanism this change removes, so it now asserts the rung instead -- through the interface, since reading a default interface member off the concrete type only compiles when the override exists and would assert nothing. Verification: full solution builds clean on 2.56.0 (-f net9.0, 0 warnings). CoreTests 2658 passed / 2 skipped / 0 failed. Wolverine.Http.Tests 992 passed / 10 skipped / 0 failed. All four --url acceptance cases driven end to end against the Quickstart sample and a stub monitor: default file unchanged; --url alone publishes and writes nothing; a down monitor prints one line and exits 1; --json and --url compose with byte-identical file and request body. Not included: the RetryBlock.ShouldRetry / OnTerminalFailure migration also unblocked by 2.56 (jasperfx#701). That is item 5 of #4012 and belongs with the three transports it touches, not here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HxbBpN6PmRB5CMSSTdGNr3
Merged
jeremydmiller
added a commit
that referenced
this pull request
Aug 26, 2026
Nine schema read-back fixes, three of which never converged: a named foreign key rebuilt a SQLite table on every run, a partition-aligned index was dropped and recreated on every run on SQL Server, and a concurrent index on a manager-owned partitioned table stayed permanently invalid. No DDL changes for a schema Weasel was already reading correctly, and no configuration changes. JasperFx is already on 2.56.0, the current release (#4153). Claude-Session: https://claude.ai/code/session_01HxbBpN6PmRB5CMSSTdGNr3 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This was referenced Aug 27, 2026
Open
This was referenced Sep 3, 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.
Closes #4152. Closes #4147. Closes #4146.
Bumps the JasperFx pins to 2.56.0 and takes the three things that unlocks.
#4152 / #4147 — provenance instead of registration order
WolverineEventModelSourceandHttpEventModelSourceboth read their roles off compiled chains, so both now declare:That lets the
services.Insert(0, ...)inUseWolverine()andMapWolverineEndpoints()become plainAddSingletoncalls. The insert was load-bearing behaviour nothing in the registration explained — the class doc had to spell it out:Both the inserts and that sentence are gone.
Note the deliberate inversion this buys, exactly as #4147 asks for: a source that observes a running system now outranks a derived one. Production truth beating what the code says it should do is the point of the ladder, not a regression.
#4146 —
event-model --urlPUTs the assembled descriptor to a monitor instead of, or as well as, writing the file:
JsonFlag's default moves from"event-model.json"tonullso--urlon its own doesn't also litter the application directory; with neither flag the command still writesevent-model.jsonexactly as before. Wolverine takes no reference on the monitor — it's an HTTP PUT to whatever URL is named.Deliberately not a
--watchflag, per the issue: this process already has the assembly loaded, so an internal loop would re-serialize the same chains forever. Only a fresh process picks up recompiled handlers, which makesdotnet watchthe mechanism rather than a workaround.The part worth reading — how the provenance change is tested
The existing GH-3988 fixture registers an overlay before
UseWolverine()and asserts the overlay may only fill gaps. That looks exactly like the regression guard for this change. It isn't — it passes with or without theDerivedstamp.The public overlay API (
EventModelSliceBuilder) can only expressTriggeredBy,InDomain,LinksToSpecification,Hotspot— annotations, none of which are factual roles. So an overlay cannot collide with a derived role, and that fixture never exercises the ladder at all. Had I stopped there I'd have shipped an "adoption" with no evidence it was load-bearing.The new
event_model_provenance_ladder_4147tests use customIEventModelDefinitionSourcestubs that do claim a colliding role, and test #4147's acceptance criteria as written — an observed source overrides a derived role, a declared one cannot.Verified red. With the stamp removed, the declared rival registered first unions into the derived role instead of losing to it:
One existing test asserted the Wolverine source was registered first. That pinned the mechanism this PR removes, so it now asserts the rung — through the interface, since reading a default interface member off the concrete type only compiles when the override exists and would assert nothing.
Verification
dotnet build wolverine.slnx -c Release -f net9.0All four
--urlacceptance cases driven end to end against the Quickstart sample and a stub monitor, not just unit-tested:event-model.jsonas before--urlalone →PUT /event-model application/json, no file writtenCould not reach the monitor at http://127.0.0.1:5601/nope: Connection refused, exit code 1, no stack trace--json+--url→ both, and the file and request body are byte-for-byte identical (8153 bytes each)-u, --urlalso confirmed to register without colliding with anyNetCoreInputflag.Not included
The
RetryBlock.ShouldRetry/OnTerminalFailuremigration also unblocked by 2.56 (jasperfx#701, noted at the bottom of #4152). That's item 5 of #4012 and belongs with the three transports it touches —RabbitMqChannelCallback,AzureServiceBusSettlement,SqsSettlement— rather than in an event-model PR. #4152's own title scopes it to the event model.Worth a follow-up look
#4152 mentions that dropped claims now surface as
HotspotOrigin.SourceDisagreement(#704) rather than being silently resolved. Nothing in the suites surfaced a disagreement between the two derived sources, but that's on this repo's fixtures, not on a real application's model — worth a glance at a substantial app'sevent-modeloutput after the bump.🤖 Generated with Claude Code
https://claude.ai/code/session_01HxbBpN6PmRB5CMSSTdGNr3