Skip to content

Bobcat core takes no JasperFx or Wolverine dependency (#744) - #755

Merged
jeremydmiller merged 8 commits into
mainfrom
decouple-jasperfx-744
Oct 19, 2026
Merged

jeremydmiller merged 8 commits into
mainfrom
decouple-jasperfx-744

Conversation

@jeremydmiller

Copy link
Copy Markdown
Member

Summary

Bobcat.dll now references no JasperFx and no Wolverine assembly, and nothing in this repository references Wolverine except Bobcat.Ui (a tool, unchanged). This implements the decided design in design/jasperfx-decoupling.md. The design note, its bdd-tools-comparison.md Discussion-log entry and its design/README.md row are part of this PR.

The Critter Stack vocabulary, the audit, the samples and the spec writer move to the Wolverine repo in JasperFx/wolverine#5082. Merge order is in the design note: this PR, then Bobcat rc.2 ships, then wolverine#5082 bumps to it.

Removed (moving to the Wolverine repo):

  • src/Bobcat/CritterStack/*, except RecordBuilding (TableRunner calls it, and its namespace is unchanged)
  • GeneratedEventModel and SpecIdentityAudit
  • The obsolete SpecificationBindings and Bobcat's SpecificationManifestAttribute
  • Bobcat.CritterStackScenario.Tests, SpecIdentityAuditTests and ResourceParsingAgreementTests
  • Every sample, build/Samples.cs (and its Npgsql reference), and samples.yml
  • import-event-model --specs (EmlangSpecWriter, SpecProjectWriter, the spec-file merge) and its flags. The board → stubs + EventModelDefinition import and its additive merge stay.

Added to core:

  • Bobcat.Resilience.DispositionKind and [ClearsOnRetry], [ClearsOnRecycle], [ClearsInFreshProcess] and [NeverRecovers], with the same members and Because. ClearsOnRecycle uses ResilienceTags.ParseResources, so there is one parser.
  • PreflightResults (Successes, Failures, Succeeded(), Assert() → PreflightException naming every failure)
  • ActTrigger, which replaces TriggerKind on [EventModelTrigger] with the same member names
  • The publishing bridge:
    • The generator emits a module initializer that calls Bobcat.Monitoring.SpecEventModels.Register(modelName, assemblyName, json). It is emitted only when the compilation has JasperFx.Events and SpecEventModels.
    • SpecEventModelPublisher publishes the registered JSON and keeps The runner never publishes its spec assembly's Event Model half — so the merge #268 enabled has nothing to merge #294's refusal of a model with a different name.
    • EventModelBridgeTests.the_bridge_registers_json_byte_identical_to_the_pin checks the bridge's JSON byte for byte against Fixtures/bridge-event-model.json. That fixture was captured from the pre-change publisher path and committed first (dcf61a5).
  • The JasperFx.Core helpers are inlined. Spectre.Console and Microsoft.Extensions.DependencyInjection / Hosting.Abstractions (9.0.0) are now core's own references. JasperFx used to bring them in.
  • BobcatAssemblyReferenceTests fails if Bobcat.dll references any JasperFx* or Wolverine* assembly.

Breaking changes (rc.2)

These are also in docs/compatibility.md#migrating-to-rc-2.

  1. CritterStackSpec/CritterStackScenario, EventStores, DocumentStores, SpecIdentityAudit, AddContainerChecks and services.EventStore() are now in WolverineFx.Bobcat, under the same namespace.
  2. JasperFx.Testing.DispositionKind and the hint attributes become Bobcat.Resilience.*.
  3. Preflight.Run returns PreflightResults.
  4. [EventModelTrigger(TriggerKind.Http, …)] becomes ActTrigger.Http.
  5. SpecificationBindings and Bobcat's SpecificationManifestAttribute are deleted.
  6. bobcat import-event-model --specs is gone. Specs come from the Wolverine-side command.
  7. A suite that got JasperFx transitively through Bobcat and uses it directly now needs its own reference.

Notes

  • Supervisor (Decouple Bobcat.Supervisor from JasperFx (follows the core decoupling) #745 is separate). Supervisor.cs and SupervisorResults.cs drop using JasperFx.Testing;. Type identity forced this, because Disposition.Kind is now Bobcat's enum. Bobcat.Supervisor.csproj never referenced JasperFx directly, so the Supervisor already builds without it. Decouple Bobcat.Supervisor from JasperFx (follows the core decoupling) #745 adds its guard test.
  • Test hosts that compile the Event Model (Bobcat.Generators.Tests, Bobcat.Xunit.Samples) reference JasperFx.Events directly, as a consumer does through WolverineFx.Bobcat. The generator tests read the store vocabulary from a compiled stand-in. The generator still recognizes Bobcat.CritterStack.CritterStackScenario/Spec by metadata name.
  • Packages. src/Directory.Packages.props drops the Marten, Fisher, Polecat, WolverineFx.Marten/Fisher/RabbitMQ and JasperFx.Events.SourceGenerator pins, along with the alignment header that described them.
  • Docs. The VitePress snippets that imported samples/ now inline that code, and their links point at the last commit that had the samples. The docs site builds.

Verification

  • dotnet build bobcat.slnx: 0 errors.
  • dotnet test --solution bobcat.slnx: 2662 total, 2627 passed, 0 failed, 35 skipped. The skips are the explicit or conditional probe tests and pending specs, all skipped by design.
  • ./build.sh Pack at 1.0.0-rc.2.local.1 produces nine packages. The Bobcat nuspec depends only on Spectre.Console and the two Microsoft.Extensions abstractions.

Closes #744

🤖 Generated with Claude Code

https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

jeremydmiller and others added 7 commits October 18, 2026 12:01
… replaces it (#744)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
… Wolverine repo (#744)

src/Bobcat/CritterStack (all but RecordBuilding, which TableRunner calls), GeneratedEventModel,
SpecIdentityAudit, the obsolete SpecificationBindings / SpecificationManifestAttribute,
Bobcat.CritterStackScenario.Tests, the audit and resource-parsing agreement tests, every
sample, build/Samples.cs (and the Npgsql it needed) and samples.yml. They ship from
WolverineFx.Bobcat under the same namespaces (wolverine#5082).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
…writer (#744)

EmlangSpecWriter, SpecProjectWriter, the spec-file merge and the --specs, --specs-out,
--specs-namespace, --app-project, --store, --bobcat-version and --wolverine-version flags
leave. The board -> stubs + EventModelDefinition import and its additive merge stay. The
example method/scenario naming the import shares with the spec writer moves to
ProjectedSpecNaming.ExampleMethodName / ExampleScenarioTitle.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
…er and the publishing bridge (#744)

- Bobcat.Resilience owns DispositionKind and [ClearsOnRetry] / [ClearsOnRecycle] /
  [ClearsInFreshProcess] / [NeverRecovers] (same members and Because); ClearsOnRecycle reads
  its resources through ResilienceTags.ParseResources, so there is one parser.
- Preflight.Run returns PreflightResults (Successes, Failures, Succeeded(), Assert() throwing a
  PreflightException naming every failure). AddContainerChecks moves to WolverineFx.Bobcat.
- [EventModelTrigger] takes ActTrigger (TriggerKind's member names); the generator stamps
  TriggerKind by member name, so the descriptor is unchanged.
- The publishing bridge: the generator emits a module initializer that registers the spec
  half with Bobcat.Monitoring.SpecEventModels as (modelName, source, json); the JSON is what
  GeneratedEventModel.For + the publisher's serializer produced, pinned byte for byte by
  EventModelBridgeTests. SpecEventModelPublisher publishes registered halves and keeps #294's
  refusal of a differently-named model.
- JasperFx.Core helpers inlined; Spectre.Console and Microsoft.Extensions.*.Abstractions are
  core's own references now. BobcatAssemblyReferenceTests guards Bobcat.dll.
- Supervisor: Supervisor.cs and SupervisorResults.cs drop using JasperFx.Testing, forced by
  type identity (Disposition.Kind is Bobcat's enum). Nothing else for #745.
- Test hosts that compile the Event Model reference JasperFx.Events directly; the generator
  tests read the store vocabulary from a compiled stand-in.
- src/Directory.Packages.props drops the store pins nothing references any more.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
…744)

CLAUDE.md and docs/agents point at WolverineFx.Bobcat for the Critter Stack vocabulary and
drop the samples' build; compatibility.md says rc.2 carries no JasperFx minimum and gains
'Migrating to 1.0.0-rc.2' with the seven breaking changes; bobcat-tool.md loses --specs;
the integration pages, ActTrigger in examples, Bobcat.Resilience for the hints, and the
VitePress snippets that imported samples/ now inline the code (their links pin the last
commit that had the samples).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
jeremydmiller added a commit to JasperFx/wolverine that referenced this pull request Oct 18, 2026
…l --specs (GH-5082)

Bobcat keeps importing an eventmodelers.ai board as stubs and EventModelDefinitions; writing WolverineFx.Bobcat
specifications for the board's examples moved here with the vocabulary they are written against
(JasperFx/bobcat#755). New package WolverineFx.Bobcat.EventModel (src/Bobcat/Wolverine.Bobcat.EventModel):

- EmlangSpecWriter and SpecProjectWriter from Bobcat.EventModel, the specification arm of its additive merge
  (SpecMerge: MergeSpecs, MergeGlobalUsings) and of ImportFileWriter (SpecFileWriter.WriteSpecs), with the
  same callout codes.
- The write-specs JasperFx command, next to scaffold: an application referencing the package runs
  `dotnet run -- write-specs board.json`. It keeps the flags --specs-out, --specs-namespace, --app-project,
  --store, --bobcat-version and --wolverine-version, plus the import's --model, --namespace, --out,
  --chapter, --aggregate, --starts-stream, --strong-typed-ids, --single-definition, --json and --force,
  and merges into the stubs only what the specifications need.
- A generated spec project pins WolverineFx.Bobcat to this package's own version and Bobcat to the version
  it was built against (stamped from Directory.Packages.props), instead of constants moved by hand.

Bobcat.EventModel 1.0.0-rc.2 keeps three members internal that the writer used. EventModelInternals reaches
CuratedScenario.Source/SourceChapter and CuratedFieldTypes.TryInfer by reflection, and copies the trivial
EmlangReader.Text, until Bobcat makes them public; it is the one file to delete then.

Tests (Wolverine.Bobcat.EventModel.Tests): EmlangSpecWriterTests, SpecProjectWriterTests and
DeclaredIdentityTests, the specification halves #755 cut from the import tests, the spec-merge arm of
ImportMergeTests plus the idempotency and --force cases for specifications, and write-specs end to end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
jeremydmiller added a commit to JasperFx/wolverine that referenced this pull request Oct 18, 2026
The test JasperFx/bobcat#755 deleted from Bobcat's TagsAndStrongTypedIdsTests, beside the store-only
vocabulary's other tests, with its own tag types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
…51.1-alpha.1 pairing (#744)

RecordedStep.Failure gets a public setter (as Recording.Failure has); CuratedScenario.Source and
SourceChapter get public getters; CuratedFieldTypes and EmlangReader.Text become public. The moved
vocabulary and spec writer (wolverine#5082) then call them directly instead of by reflection.

compatibility.md: WolverineFx.Bobcat 6.51.1-alpha.1 is the rc.1 pairing (ends the #742 limit), and
does not run on rc.2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
@jeremydmiller
jeremydmiller merged commit 8060184 into main Oct 19, 2026
4 checks passed
@jeremydmiller jeremydmiller mentioned this pull request Oct 19, 2026
jeremydmiller added a commit that referenced this pull request Oct 19, 2026
… test says so (#745)

#755 already took the supervisor's last JasperFx usings out; this pins it like core's guard.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
jeremydmiller added a commit to JasperFx/wolverine that referenced this pull request Oct 19, 2026
…tion bridges

Bobcat rc.2 made RecordedStep.Failure, CuratedScenario.Source/SourceChapter, CuratedFieldTypes and
EmlangReader.Text public (JasperFx/bobcat#755), so EventModelInternals and failStep go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk
jeremydmiller added a commit that referenced this pull request Oct 19, 2026
… test says so (#745) (#757)

#755 already took the supervisor's last JasperFx usings out; this pins it like core's guard.


Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
jeremydmiller added a commit to JasperFx/wolverine that referenced this pull request Oct 19, 2026
…es and the spec writer (#5082) (#5083)

* WolverineFx.Bobcat takes the Critter Stack vocabulary from Bobcat core (GH-5082)

Bobcat 1.0.0-rc.2 (JasperFx/bobcat#755) drops every JasperFx, JasperFx.Events and Wolverine dependency
from core, so the store-agnostic vocabulary moves here, keeping its namespaces:

- src/Bobcat/Wolverine.Bobcat/CritterStack: CritterStackScenario, CritterStackSpec, CritterStackActOutcome,
  EventStores, DocumentStores, StoreRouting, EventStoreAuthoring, CritterStackHostExtensions,
  ProjectionsBehind and the two timeout exceptions (Bobcat.CritterStack). RecordBuilding stays in core.
- EventModel/GeneratedEventModel and SpecIdentityAudit (Bobcat).
- Preflight.AddContainerChecks, now an extension method over Bobcat's Preflight (JasperFx's
  EnvironmentChecker), so a call site reads as before.
- [EventModelTrigger(TriggerKind.Http, ...)] is [EventModelTrigger(ActTrigger.Http, ...)].

One core internal is reached by reflection until Bobcat exposes it: RecordedStep.Failure has an
internal setter, and recordTimedOutAct (bobcat#673) sets it on the open When step.

Tests: Bobcat.CritterStackScenario.Tests moves beside Wolverine.Bobcat.Tests (Marten on this repo's
Postgres through Servers, Fisher on temp SQLite, [PostgresFact] never skipping with CI=true), now on
net9.0 and net10.0 and in CIBobcat. The SpecIdentityAudit tests and CritterStackSpecRoleTests move into
Wolverine.Bobcat.Tests, the role specs compiled as this assembly's own projected specs.

Running them on net9.0 exposed an order-dependent bug the net10.0-only Bobcat run never hit: a
tenant's first read in a fresh schema threw Marten's immediate "No event activity was detected"
(the #497 empty-store case, fixed then for the untenanted wait only). The tenant wait now returns
at once when the tenant's own view holds no events on a single-database store.

Bobcat comes from a local preview feed (NuGet.config, 1.0.0-rc.2.local.1) until rc.2 publishes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

* Bobcat's samples move here, with the targets and workflow that run them (GH-5082)

All 13 samples from the Bobcat repository (JasperFx/bobcat#755) land in src/Samples/Bobcat with their
README, sample-projects.md, docker-compose.yml, init scripts and LICENSE. They are written against the
Critter Stack vocabulary that now ships in WolverineFx.Bobcat.

- They reference this repository's Wolverine projects (and WolverineFx.Bobcat) by ProjectReference, the
  way src/Samples consumes Wolverine, and Bobcat, Bobcat.Xunit and Bobcat.Generators as packages, so the
  packages' buildTransitive props apply as for any consumer. Directory.Build.props adds those four to
  every Tests project.
- Directory.Packages.props imports the repository's own, so the samples run on exactly its Marten, Fisher,
  JasperFx.Events, xUnit and Alba. Only the Aspire packages and Wolverine.CritterWatch are pinned there;
  CritterWatch moves from a local-feed 1.0.2-vehicle.1 to the published 1.1.0-rc.1, whose WolverineFx
  6.51.0 dependency the ProjectReference satisfies, and BankAccountES's NuGet.config goes.
- build/BobcatSamples.cs carries Bobcat's Samples targets as CompileBobcatSamples, TestBobcatSamples
  (one Postgres database per sample, on this repo's docker-compose Postgres, 5433) and
  TestBobcatSamplesOnFisher (BankAccountES on a SQLite file). bobcat-samples.yml runs BobcatSamples.
- BankAccountES's TriggerKind becomes ActTrigger. Its EventModel specs pinned wolverine#4975's
  Query-vs-View disagreement so that the fix would turn them red, and against this repository's
  Wolverine it did: the GET slices now assert a Query reading its response type, with no disagreement.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

* write-specs: the spec writer moves here from bobcat import-event-model --specs (GH-5082)

Bobcat keeps importing an eventmodelers.ai board as stubs and EventModelDefinitions; writing WolverineFx.Bobcat
specifications for the board's examples moved here with the vocabulary they are written against
(JasperFx/bobcat#755). New package WolverineFx.Bobcat.EventModel (src/Bobcat/Wolverine.Bobcat.EventModel):

- EmlangSpecWriter and SpecProjectWriter from Bobcat.EventModel, the specification arm of its additive merge
  (SpecMerge: MergeSpecs, MergeGlobalUsings) and of ImportFileWriter (SpecFileWriter.WriteSpecs), with the
  same callout codes.
- The write-specs JasperFx command, next to scaffold: an application referencing the package runs
  `dotnet run -- write-specs board.json`. It keeps the flags --specs-out, --specs-namespace, --app-project,
  --store, --bobcat-version and --wolverine-version, plus the import's --model, --namespace, --out,
  --chapter, --aggregate, --starts-stream, --strong-typed-ids, --single-definition, --json and --force,
  and merges into the stubs only what the specifications need.
- A generated spec project pins WolverineFx.Bobcat to this package's own version and Bobcat to the version
  it was built against (stamped from Directory.Packages.props), instead of constants moved by hand.

Bobcat.EventModel 1.0.0-rc.2 keeps three members internal that the writer used. EventModelInternals reaches
CuratedScenario.Source/SourceChapter and CuratedFieldTypes.TryInfer by reflection, and copies the trivial
EmlangReader.Text, until Bobcat makes them public; it is the one file to delete then.

Tests (Wolverine.Bobcat.EventModel.Tests): EmlangSpecWriterTests, SpecProjectWriterTests and
DeclaredIdentityTests, the specification halves #755 cut from the import tests, the spec-merge arm of
ImportMergeTests plus the idempotency and --force cases for specifications, and write-specs end to end.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

* EventTagQueryDescriptionTests moves with EventStores.Describe (GH-5082)

The test JasperFx/bobcat#755 deleted from Bobcat's TagsAndStrongTypedIdsTests, beside the store-only
vocabulary's other tests, with its own tag types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

* Bobcat 1.0.0-rc.2 from nuget.org; drop the local feed and both reflection bridges

Bobcat rc.2 made RecordedStep.Failure, CuratedScenario.Source/SourceChapter, CuratedFieldTypes and
EmlangReader.Text public (JasperFx/bobcat#755), so EventModelInternals and failStep go.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YDKQhnBVcmVLCTkJbVeADk

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decouple Bobcat core from JasperFx entirely (breaking, before 1.0)

1 participant