Skip to content

The renderer package hands every consumer the runtime it generates code for #34

Description

@woksin

Cratis.Stage.Rendering.Cratis hands every consumer the Arc + Chronicle + MongoDB runtime it generates code for, and cannot simply stop.

The renderer is a text generator. Its own csproj says so, in a comment that is currently untrue:

<!--
    Specs compile the rendered output in memory against the real Cratis assemblies … These are private
    assets: the renderer itself does not depend on Cratis at runtime, only its specs do.
-->
<PackageReference Include="Cratis" ExcludeAssets="analyzers" />
<PackageReference Include="Cratis.Arc.MongoDB" ExcludeAssets="analyzers" />

PrivateAssets is not set on either, so both flow to every consumer.

Measured

The published package declares them. From cratis.stage.rendering.cratis.2.3.0.nupkg's nuspec:

<dependency id="Cratis" version="21.13.0" exclude="Build,Analyzers" />
<dependency id="Cratis.Arc.MongoDB" version="21.13.0" exclude="Build,Analyzers" />

What that costs a consumer. Adding Cratis.Stage.Rendering.Cratis to the CLI — which is the whole of Cratis/cli#62, cratis render — produces:

  • 160 compilation errors, all ambiguity. The Cratis package contributes GlobalUsings.cs through its Cratis.props, so every consuming project silently gains 28 global usings. User becomes ambiguous between Cratis.Arc.Identity.User and Cratis.Chronicle.Contracts.Security.User, AppendedEvent between Cratis.Chronicle.Events and Cratis.Chronicle.Contracts.Events, and so on.
  • error MSBL001 — the template engine brings NuGet.Frameworks transitively, and Microsoft.Build.Locator refuses to run when a copy sits beside the executable. The CLI uses MSBuildLocator for screenplay generate.
  • A version collision. The CLI pins Cratis.Chronicle.Contracts 16.19.3 deliberately (Chronicle 16.20.0 validates TLS by default, so the CLI can no longer connect to a local server out of the box cli#67 — Chronicle 16.20.0's TLS default). This package wants the 16.28.0 line through Arc 21.13.0.

PrivateAssets="all" alone does not fix it

Tried, and reverted: it produces a clean nuspec (both dependencies gone, everything still builds, all 254 specs pass), but the assembly it packages would then have unsatisfiable references.

Reading the AssemblyRef table of the Release build — specs stripped — with System.Reflection.Metadata:

Cratis.Arc            Cratis.Arc.Chronicle   Cratis.Arc.Core     Cratis.Arc.MongoDB
Cratis.Arc.Swagger    Cratis.Chronicle       Cratis.Chronicle.AspNetCore
Cratis.Chronicle.Connections                 Cratis.Chronicle.Infrastructure

and 557 type references into them — AggregateRoot, AggregateRootMutatorFactory, EventsCommandResponseValueHandler, the whole surface, in alphabetical sweeps. That is the shape of a type-discovery registration, not of code anyone wrote: no production file in Rendering.Cratis names an Arc or Chronicle type. The only mentions are string literals the renderer emits into generated files (builder.Using("Cratis.Chronicle.Events")), and those live in the #US heap as UTF-16 — Cratis.Arc.MongoDB appears twice as ASCII metadata and zero times as a literal, which is how you tell the two apart.

So ExcludeAssets="analyzers" on the two direct references is not stopping the generator: it still runs — presumably reaching the compilation through another contributor — and bakes the registration in. The csproj comment above already anticipates exactly this ("Cratis' type-discovery source generator would bake a registration into this assembly that binds the Cratis runtime at startup, which the renderer — a text generator — has no reason to do"); it just is not achieving it.

What closing this needs

  1. Stop the generator running for this assembly — find which reference still contributes the analyzer and exclude it there too, then confirm the AssemblyRef table holds only Cratis.Screenplay, Cratis.Stage.Contracts, the template engine and the BCL.
  2. Then mark Cratis and Cratis.Arc.MongoDB PrivateAssets="all", so the package declares only what the renderer needs to run.
  3. Guard it: read the AssemblyRef table in a spec and assert on the set. It is four lines with System.Reflection.Metadata and it would have caught this the day it appeared.

Worth pairing with a decision on the template engine: Cratis.Templates + three Microsoft.TemplateEngine.* packages exist only to scaffold a target project on first render. A consumer that renders into a project it already has pays for all four, and pays MSBL001 if it also hosts MSBuild. Splitting scaffolding out of Rendering.Cratis would leave the renderer as what it claims to be — a text generator with no runtime.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions