Skip to content

Fix Cratis meta-package and Chronicle consumption for downstream apps#2310

Closed
woksin wants to merge 4 commits into
mainfrom
fix/cratis-meta-package-consumption
Closed

Fix Cratis meta-package and Chronicle consumption for downstream apps#2310
woksin wants to merge 4 commits into
mainfrom
fix/cratis-meta-package-consumption

Conversation

@woksin

@woksin woksin commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Makes Arc consumable again from the Cratis meta package alongside Arc.Chronicle. Arc 20.44.0 broke real consumers at build and runtime; this restores a clean restore-build-run path against released Chronicle.

Changed

  • Raised the minimum required Cratis.Chronicle to 15.35.0.

Fixed

  • Building a project that references the Cratis meta package together with a package that transitively brings Cratis.Arc.Core (such as Cratis.Arc.MongoDB) no longer fails with CS0101 'Cratis.Arc.Generated.GeneratedMarker' caused by the Arc source generator being loaded and run twice.
  • Arc no longer throws MissingMethodException at runtime against released Chronicle. The Chronicle floor now matches the AppendMany/Append overloads Arc actually calls, so an incompatible Chronicle version fails dotnet restore instead of crashing at runtime.
  • The ARCCHR0002 analyzer no longer reports an ambiguous command event source id when the command's Handle supplies the event source explicitly through a tuple return — including new-stream-create commands that return a generated id deriving from EventSourceId<T>.

woksin added 4 commits June 21, 2026 10:37
Arc 20.44.0 was compiled against a Chronicle whose IEventSequence.AppendMany
signature differed from the released one consumers restore. 15.35.0 added a
trailing optional 'Subject? subject' parameter to AppendMany/Append, which
modifies the single method signature rather than adding an overload, so Arc
compiled against the older signature bound to a method that no longer exists
and threw MissingMethodException at runtime against released Chronicle.

- Pin the Chronicle floor to released 15.35.0 and align the Microsoft.Extensions
  family to 10.0.9 (required by Chronicle 15.35.0) so a version mismatch fails
  restore instead of crashing at runtime.
- Add a reflection guard spec pinning the AppendMany/Append overload signatures
  the command pipeline binds to, so a future Chronicle signature drift trips at
  build time instead of reaching consumers as a runtime crash.
The Cratis meta package bundles the Arc source generator into analyzers/dotnet/cs,
and the individual packages (Cratis.Arc.Core, Cratis.Fundamentals) ship the same
generator. A consumer referencing Cratis plus any package that transitively brings
one of those (e.g. Cratis.Arc.MongoDB -> Cratis.Arc.Core) loaded the generator from
two analyzer paths, ran it twice, and failed with CS0101 because the unconditional
'Cratis.Arc.Generated.GeneratedMarker' was emitted twice.

- Add a buildTransitive target in Cratis.props that de-duplicates @(Analyzer) by
  file name before compilation, so every Cratis consumer collapses duplicate
  analyzer DLLs regardless of restore path (this also protects GeneratedQueryMetadata).
- Make GeneratedMarker a partial type as defense-in-depth, so a duplicate emission
  merges instead of colliding even if an analyzer slips through de-duplication.
- Cover the partial-merge defense with a unit spec that compiles two copies of the
  generated marker and asserts no CS0101.
Reproduce the analyzer double-load end to end: pack the meta-package closure into a
local feed and build a consumer that references both Cratis and Cratis.Arc.MongoDB
with a [ReadModel], asserting it builds clean with no CS0101. The read model makes
the generator emit GeneratedQueryMetadata too, so the test specifically exercises the
analyzer de-duplication rather than only the partial-marker defense.
ARCCHR0002 (ambiguous command event source id) only exempted commands whose Handle
returns EventForEventSourceId directly, so it false-positived on commands that supply
the event source explicitly through a tuple return.

Do not report the diagnostic when the Handle return type is, or is a tuple containing,
EventForEventSourceId / IEnumerable<EventForEventSourceId>, or is a tuple whose first
element derives from EventSourceId<T> (new-stream create, where the event source is the
returned/generated id rather than a command property and ICanProvideEventSourceId is
neither needed nor implementable). The ambiguity warning still fires when a tuple return
provides no event source.
@woksin woksin added the patch label Jun 21, 2026
@github-actions

Copy link
Copy Markdown

NuGet packages for this PR, e.g. Cratis.Arc:
https://github.com/cratis/arc/packages/1655206?version=20.44.2

/// </summary>
static readonly string[] _projectsToPack =
[
Path.Combine("Source", "DotNET", "Arc.Core", "Arc.Core.csproj"),
static readonly string[] _projectsToPack =
[
Path.Combine("Source", "DotNET", "Arc.Core", "Arc.Core.csproj"),
Path.Combine("Source", "DotNET", "Arc", "Arc.csproj"),
[
Path.Combine("Source", "DotNET", "Arc.Core", "Arc.Core.csproj"),
Path.Combine("Source", "DotNET", "Arc", "Arc.csproj"),
Path.Combine("Source", "DotNET", "Chronicle", "Chronicle.csproj"),
Path.Combine("Source", "DotNET", "Arc.Core", "Arc.Core.csproj"),
Path.Combine("Source", "DotNET", "Arc", "Arc.csproj"),
Path.Combine("Source", "DotNET", "Chronicle", "Chronicle.csproj"),
Path.Combine("Source", "DotNET", "Swagger", "Swagger.csproj"),
Path.Combine("Source", "DotNET", "Arc", "Arc.csproj"),
Path.Combine("Source", "DotNET", "Chronicle", "Chronicle.csproj"),
Path.Combine("Source", "DotNET", "Swagger", "Swagger.csproj"),
Path.Combine("Source", "DotNET", "Tools", "ProxyGenerator.Build", "ProxyGenerator.Build.csproj"),
Path.Combine("Source", "DotNET", "Chronicle", "Chronicle.csproj"),
Path.Combine("Source", "DotNET", "Swagger", "Swagger.csproj"),
Path.Combine("Source", "DotNET", "Tools", "ProxyGenerator.Build", "ProxyGenerator.Build.csproj"),
Path.Combine("Source", "DotNET", "MongoDB", "MongoDB.csproj"),
Path.Combine("Source", "DotNET", "Swagger", "Swagger.csproj"),
Path.Combine("Source", "DotNET", "Tools", "ProxyGenerator.Build", "ProxyGenerator.Build.csproj"),
Path.Combine("Source", "DotNET", "MongoDB", "MongoDB.csproj"),
Path.Combine("Source", "DotNET", "Cratis", "Cratis.csproj"),
public static CratisMetaConsumerBuildResult Execute()
{
var repositoryRoot = GetRepositoryRoot();
var workingDirectory = Path.Combine(Path.GetTempPath(), "Cratis.Arc.MetaConsumer.Integration", Guid.NewGuid().ToString("N"));
{
var repositoryRoot = GetRepositoryRoot();
var workingDirectory = Path.Combine(Path.GetTempPath(), "Cratis.Arc.MetaConsumer.Integration", Guid.NewGuid().ToString("N"));
var packageDirectory = Path.Combine(workingDirectory, "packages");
var repositoryRoot = GetRepositoryRoot();
var workingDirectory = Path.Combine(Path.GetTempPath(), "Cratis.Arc.MetaConsumer.Integration", Guid.NewGuid().ToString("N"));
var packageDirectory = Path.Combine(workingDirectory, "packages");
var restoredPackagesDirectory = Path.Combine(workingDirectory, "restored-packages");
@woksin

woksin commented Jun 21, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #2312, which consolidates this PR and #2311 into a single PR (and adds the per-TFM dependency baseline fix). Closing in favor of #2312.

@woksin woksin closed this Jun 21, 2026
@woksin woksin deleted the fix/cratis-meta-package-consumption branch June 21, 2026 09:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant