Repository navigation
perf(build): isolate implementation edits with reference assemblies - #11653
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
The unpublished text-emission prerequisite and cross-compiler integration contracts require maintainer verification of landing order and refreshed C#/F# build evidence beyond this source-only review.
No open issues 🎉
What changed in this PR
This PR enables reference assemblies throughout the Orleans build graph to prevent implementation-only edits from recompiling downstream projects, while preserving serializer dependency metadata. The aggregate diff also includes prerequisite generator, analyzer, test-graph, and CI optimizations; those layers, including the text-emission migration, must land first.
Changes:
- Enable reference assembly production, retain reference-visible serializer contracts, and explicitly select implementation metadata for the raw external-model test consumer.
- Reuse generator discoveries and emission plans, write generated source directly, and expand regression tests and snapshots.
- Reduce repeated build, analyzer, restore, and CI work through focused test graphs, dependency caches, and incremental build orchestration.
Build and test evidence is reported in the PR description; automated coverage results were not available in the supplied context.
| File | Description |
|---|---|
test/Orleans.Serialization.UnitTests/Orleans.Serialization.UnitTests.csproj |
Links shared helpers and selects external-model implementation metadata. |
test/Orleans.DefaultCluster.Tests/Orleans.DefaultCluster.Tests.csproj |
Removes the generator-test project dependency. |
test/Orleans.DefaultCluster.Tests/GrainActivateDeactivateTests.cs |
Adds an explicit Xunit import. |
test/Orleans.CodeGenerator.Tests/SourceWriterTests.cs |
Tests direct source layout and lexical spelling. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithSuppressReferenceTrackingAttribute.verified.cs |
Records dependency contracts for suppressed reference tracking. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestWithOmitDefaultMemberValuesAnnotation.verified.cs |
Records dependency contracts for omitted default values. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecordsWithParameterIdAttributes.verified.cs |
Records the parameter-ID record contract. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestRecords.verified.cs |
Records the record-struct contract. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGrainComplexGrain.verified.cs |
Records complex grain-payload contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.UnsafeAccessor.verified.cs |
Records generic constructor dependencies with unsafe accessors. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClassWithConstructorParameters.FieldAccessor.verified.cs |
Records generic constructor dependencies with field accessors. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestGenericClass.verified.cs |
Records open and constructed generic contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestCompoundTypeAlias.verified.cs |
Records contracts for compound-alias models. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithParameterizedConstructor.verified.cs |
Records parameterized-constructor model dependencies. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassWithGenerateSerializerAnnotation.verified.cs |
Records implicit-field and enum contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypesUsingFullName.verified.cs |
Records primitive-array dependency contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassPrimitiveTypes.verified.cs |
Records primitive-model dependency contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassNestedTypes.verified.cs |
Records nested and cyclic model dependencies. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestClassesWithGeneratedActivatorConstructorAnnotation.verified.cs |
Records generated-activator model contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicStruct.verified.cs |
Records the basic struct codec contract. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithoutNamespace.verified.cs |
Records global-namespace model contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClassWithDifferentAccessModifiers.verified.cs |
Records public and internal model contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestBasicClass.verified.cs |
Records basic class codec and copier contracts. |
test/Orleans.CodeGenerator.Tests/snapshots/OrleansSourceGeneratorTests.TestAlias.verified.cs |
Records the aliased struct contract. |
test/Orleans.CodeGenerator.Tests/SerializerOutputOrderingTests.cs |
Tests canonical output ordering and hint collisions. |
test/Orleans.CodeGenerator.Tests/SerializerInitializationTests.cs |
Adapts registration tests to direct text emission. |
test/Orleans.CodeGenerator.Tests/SerializerConstructionPlanningTests.cs |
Tests construction parity, dependencies, and graph limits. |
test/Orleans.CodeGenerator.Tests/ReferencedSerializerContextTests.cs |
Keeps legacy fixtures free of new dependency contracts. |
test/Orleans.CodeGenerator.Tests/OrleansSourceGeneratorTests.cs |
Normalizes contract versions for cross-framework snapshots. |
test/Orleans.CodeGenerator.Tests/Orleans.CodeGenerator.Tests.csproj |
Links test traits and adds the focused F# fixture. |
test/Orleans.CodeGenerator.Tests/ImplementationSourceOutputTests.cs |
Extends partial-context implementation-output coverage. |
test/Orleans.CodeGenerator.Tests/GeneratedSourceOutputTests.cs |
Tests source deduplication and collision handling. |
test/Orleans.CodeGenerator.Tests/GeneratedSourceLayoutTests.cs |
Checks generated layout and compilation across output kinds. |
test/Orleans.Analyzers.Tests/SymbolHelpersTest.cs |
Tests attribute lookup on metadata symbols. |
test/Orleans.Analyzers.Tests/InvalidIdentityAttributeAnalyzerTest.cs |
Tests identity fast paths and exact diagnostics. |
test/Orleans.Analyzers.Tests/IncorrectAttributeUseAnalyzerTest.cs |
Tests aliased attributes on partial grains. |
test/Orleans.Analyzers.Tests/IdClashAttributeAnalyzerTest.cs |
Tests duplicate-ID locations across partial declarations. |
test/Orleans.Analyzers.Tests/GrainInterfacePropertyDiagnosticAnalyzerTest.cs |
Tests interface-only property analysis. |
test/Orleans.Analyzers.Tests/GrainInterfaceMethodReturnTypeDiagnosticAnalyzerTest.cs |
Tests indexed proxy resolution and diagnostic ordering. |
test/Orleans.Analyzers.Tests/GenerateSerializationAttributesAnalyzerTest.cs |
Tests field-ID exclusions and partial declarations. |
test/Orleans.Analyzers.Tests/GenerateGenerateSerializerAttributeAnalyzerTest.cs |
Tests serializer attributes across partial declarations. |
test/Orleans.Analyzers.Tests/GenerateAliasAttributesAnalyzerTest.cs |
Tests alias detection across partial types and methods. |
test/Orleans.Analyzers.Tests/AtMostOneOrleansConstructorAnalyzerTest.cs |
Tests partial-type constructor diagnostics. |
test/Orleans.Analyzers.Tests/AbstractPropertiesCannotBeSerializedAnalyzerTest.cs |
Tests exact invalid-member attribute spans. |
test/Misc/TestSerializerExternalModels/TestSerializerExternalModels.csproj |
Removes the reference assembly opt-out. |
test/Grains/TestVersionGrains2/TestVersionGrains2.csproj |
Uses build output for the second silo deployment. |
test/Grains/TestVersionGrains/TestVersionGrains.csproj |
Uses build output for the first silo deployment. |
test/Grains/TestGrainInterfaces/EventSourcing/XDocumentSerialization.cs |
Extracts the shared XML codec and surrogate. |
test/Grains/TestGrainInterfaces/EventSourcing/IChatGrain.cs |
Removes XML helpers moved to their own file. |
test/Grains/TestFSharpModels/TestFSharpModels.fsproj |
Adds a focused F# model fixture. |
test/Grains/TestFSharp/TestFSharp.fsproj |
Removes the F# reference assembly opt-out. |
src/Orleans.Streaming/Orleans.Streaming.csproj |
Removes the streaming reference assembly opt-out. |
src/Orleans.Reminders/Orleans.Reminders.csproj |
Removes the reminders reference assembly opt-out. |
src/Orleans.DurableJobs/Orleans.DurableJobs.csproj |
Removes the durable-jobs reference assembly opt-out. |
src/Orleans.CodeGenerator/SyntaxGeneration/SyntaxFactoryUtility.cs |
Produces spelled generic constraints. |
src/Orleans.CodeGenerator/SyntaxGeneration/SymbolSyntaxExtensions.cs |
Removes the obsolete binding-flags syntax builder. |
src/Orleans.CodeGenerator/SyntaxGeneration/StringExtensions.cs |
Removes the replaced literal-expression helper. |
src/Orleans.CodeGenerator/SyntaxGeneration/FSharpUtils.cs |
Represents F# accessors as member-access plans. |
src/Orleans.CodeGenerator/SyntaxGeneration/CodeText.cs |
Adds lexical C# text helpers. |
src/Orleans.CodeGenerator/SourceWriter.cs |
Adds direct source layout and indentation handling. |
src/Orleans.CodeGenerator/SourceGeneratorResults.cs |
Carries emission plans, owner identity, and current diagnostic locations. |
src/Orleans.CodeGenerator/SerializerContextGenerator.cs |
Writes context declarations and implementations directly. |
src/Orleans.CodeGenerator/SerializableSourceOutputGenerator.cs |
Plans per-owner serializers, copiers, and activators. |
src/Orleans.CodeGenerator/ReferenceAssemblyDataProvider.cs |
Passes source discoveries into metadata extraction. |
src/Orleans.CodeGenerator/ProxyGenerationContext.cs |
Retains proxy and compatibility invokable plans. |
src/Orleans.CodeGenerator/OrleansSourceGenerator.cs |
Connects cached emission and single-owner context generation. |
src/Orleans.CodeGenerator/Model/TypeMetadataIdentity.cs |
Uses raw namespace components for metadata identities. |
src/Orleans.CodeGenerator/Model/SerializableTypeModel.cs |
Clarifies the discovery model’s documented role. |
src/Orleans.CodeGenerator/Model/ReferenceAssemblyModelExtractor.cs |
Reuses discoveries and formats type names lazily. |
src/Orleans.CodeGenerator/Model/ProxyEmissionPlan.cs |
Adds structured proxy declaration plans. |
src/Orleans.CodeGenerator/Model/ModelExtractor.cs |
Forwards reusable source models. |
src/Orleans.CodeGenerator/Model/InvokableEmissionPlan.cs |
Adds structured invokable declaration plans. |
src/Orleans.CodeGenerator/Model/GeneratedProxyDescription.cs |
Removes the replaced proxy description type. |
src/Orleans.CodeGenerator/Model/GeneratedInvokableDescription.cs |
Stores an emission plan instead of declaration syntax. |
src/Orleans.CodeGenerator/Model/EnumSerializerPlan.cs |
Defines enum emission plans and dependency metadata. |
src/Orleans.CodeGenerator/MetadataSourceOutputGenerator.cs |
Composes metadata output using direct writers. |
src/Orleans.CodeGenerator/LibraryTypes.cs |
Lazily shares serialization-library type spellings. |
src/Orleans.CodeGenerator/GeneratedTypeConstruction.cs |
Shares constructor and dependency descriptions. |
src/Orleans.CodeGenerator/GeneratedCodeUtilities.cs |
Supplies generated attributes as text. |
src/Orleans.CodeGenerator/EnumSerializerGenerator.cs |
Emits planned enum codecs with dependency contracts. |
src/Orleans.CodeGenerator/ApplicationPartAttributeGenerator.cs |
Emits application-part attributes directly as text. |
src/Orleans.CodeGenerator/ActivatorGenerator.cs |
Separates activator planning from text emission. |
src/Orleans.BroadcastChannel/Orleans.BroadcastChannel.csproj |
Removes the broadcast-channel reference assembly opt-out. |
src/Orleans.Analyzers/SymbolHelpers.cs |
Avoids syntax retrieval for existence-only attribute checks. |
src/Orleans.Analyzers/InvalidIdentityAttributeAnalyzer.cs |
Skips unavailable identity types and argument-free attributes. |
src/Orleans.Analyzers/GrainInterfacePropertyDiagnosticAnalyzer.cs |
Restricts property binding to interface declarations. |
src/Orleans.Analyzers/GrainInterfaceMethodReturnTypeDiagnosticAnalyzer.cs |
Indexes method contexts by declaring interface. |
src/Orleans.Analyzers/GenerateSerializationAttributesAnalyzer.cs |
Applies the public-properties exclusion before member analysis. |
src/Dashboard/Orleans.Dashboard.App/README.md |
Documents frontend invalidation and discovery overhead. |
Orleans.slnx |
Includes the focused F# model project. |
docs/site/src/content/docs/host/configuration-guide/snippets/serializer-contexts/SerializerContexts.csproj |
Removes the documentation fixture’s reference assembly opt-out. |
Directory.Build.targets |
Scopes Roslyn registration checks to authoring projects. |
Directory.Build.props |
Enables reference assemblies and clarifies stable Debug versioning. |
CONTRIBUTING.md |
Documents incremental build commands and explicit version suffixes. |
common.ps1 |
Preserves argument boundaries and native failure exit codes. |
build.ps1 |
Adds compile-only modes and avoids redundant restore. |
Build.cmd |
Forwards all arguments to the PowerShell script. |
.github/workflows/test-build.yml |
Runs build-script regressions on both PowerShell hosts. |
.github/workflows/test-action-retry.yml |
Exercises solution-filter forwarding through retries. |
.github/workflows/macos-tests.yml |
Adds npm caching and focused CodeGen execution. |
.github/workflows/generate-api-diffs.yml |
Uses cached dependencies and shared API build traversal. |
.github/workflows/ci.yml |
Integrates caches, focused graphs, and build regression checks. |
.github/solutions/README.md |
Documents focused test graphs and inventory validation. |
.github/solutions/CodeGenerator.slnf |
Selects the two CodeGen test roots. |
.github/scripts/test-dependency-cache.ps1 |
Checks separation of dashboard and Firebase cache keys. |
.github/scripts/test-codegenerator-graph.ps1 |
Compares full and focused CodeGen test inventories. |
.github/scripts/invoke-restore.ps1 |
Accepts the selected solution graph. |
.github/scripts/generate-api.proj |
Shares restore and build work before API generation. |
.github/roslyn-non-authoring.globalconfig |
Disables registration-only rules outside authoring projects. |
.github/coverage-inputs.txt |
Tracks restore and solution-filter coverage inputs. |
.github/actions/setup-test-environment/action.yml |
Reuses the NuGet dependency store. |
.github/actions/run-tests/test-fixture/action.yml |
Verifies solution selection during retry tests. |
.github/actions/run-tests/action.yml |
Forwards the selected graph to both attempts. |
.github/actions/dotnet-test/action.yml |
Uses the selected graph for restore and testing. |
.github/actions/cache-dependencies/action.yml |
Caches dependency stores by tool, manifest, and policy identity. |
Review effort: Balanced
3c7b404 to
9a7fd95
Compare
| } | ||
| } | ||
|
|
||
| return FindCompilationAssembly(identity); |
Code coverage
Report-only conclusion: improved. The current-main baseline is commit Coverage combines every CI test matrix job, including providers, CodeGen, .NET 8/10, Linux, Windows, and macOS, using canonical physical source and branch identities. The comparison remains report-only while normal line and branch variance is calibrated. Coverage details |
9a7fd95 to
092c205
Compare
092c205 to
cbf426e
Compare
cbf426e to
c66ef82
Compare
Carry authoritative codec and copier dependencies through reference emission using versioned assembly metadata. Preserve legacy producer inspection and explicit diagnostics while keeping public APIs, constructors, and wire contracts unchanged.
Enable the repository default for netstandard and executable projects and remove the remaining fixture opt-outs. Keep raw external model serializer generation on its explicitly resolved implementation metadata edge while ordinary consumers use the produced reference assembly.
c66ef82 to
972fc31
Compare
Require serialized member types to be nameable from the external code-generation assembly, honoring friend access and preserving supported private-field accessors. Report unsupported external setter diagnostics without foreign source locations, while retaining producer-owned diagnostic locations and serializer-context dependency contracts.
There was a problem hiding this comment.
🔵 Needs a closer look
Exact-identity binding can reject compatible newer dependencies used only by private serialized state when reference emission removes their AssemblyRef, causing ORLEANS0115 in a case the current retargeting test misses.
Review effort: Balanced
There was a problem hiding this comment.
🟡 Changes recommended
The type identity check can accept a shadowed generic argument and register the wrong closed codec, leaving the producer’s dependency unresolved; complete constructed-type validation and a regression test are needed.
2 open issues
Review effort: Balanced
| if (visitedContexts.Contains(linked)) return null; | ||
| if (depth >= 128 || visitedContexts.Count >= 1024) | ||
| return new(linked, "the linked context graph exceeds 128 nested dependencies or 1024 contexts"); |
| || !compilation.IsSymbolAccessibleWithin(linked, symbol) | ||
| || !linked.InstanceConstructors.Any(constructor => constructor.Parameters.Length == 0 | ||
| && compilation.IsSymbolAccessibleWithin(constructor, symbol))) |
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved generator issues reject valid reference-assembly compositions through incorrect transitive-constructor accessibility checks and array dependency planning, while include-depth validation remains import-order dependent.
4 open issues
Review effort: Balanced
| failure = new(type, "the dependency graph exceeds 1024 closed types; declare a finite serialization graph"); | ||
| return false; | ||
| } | ||
| registrations.Add(type, new Registration(type, isProvided: true)); |
Rename the unshipped context surface to one consistent family: GeneratedContext, GeneratedContextTypeAttribute<T>, GeneratedContextImportAttribute<TContext>, and AddGeneratedContext. The previous OrleansSerializable and SerializerContext names were easy to confuse with GenerateSerializer and with serializers themselves; a context can also cover generic grain and method types. None of these APIs appear in a released package (introduced after v10.4.2), so no compatibility suppressions are needed.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved generator defects reject valid transitive imports and supplied array roots, while allowing over-depth import graphs depending on import order.
5 open issues
Preserve binding for contract-only dependency references Keep supplied array roots opaque during dependency planning · New Keep supplied array roots opaque during dependency planning Validate constructor access where each include emits its call Validate maximum include depth independently of traversal order
Review effort: Balanced
| registration.CopierConstruction = ConstructGenerated(registration.Copier, copierConstruction); | ||
| registration.HasBaseCodec = codecConstruction.HasBaseContract; | ||
| registration.HasBaseCopier = copierConstruction.HasBaseContract; | ||
| return AddCanonicalArrays(registration, named, definitionModel, codecConstruction, copierConstruction, services, cancellationToken); |


Enable reference assemblies for ordinary build targets so implementation-only edits skip downstream compilation, while preserving serialization metadata at its owning boundary.
This is the focused layer on main
836de2014a92977fca0692dc10f3965912dc635c, with no unmerged text-generation or other optimization dependency. Engineering scripts and CI workflows are unchanged.Generated contexts
Compile-time registrations use one consistent API family:
GeneratedContext— the base class for a partial class whose closed registrations are source-generated.[GeneratedContextType<T>]— declares a closed root type, such asList<Order>orDictionary<string, Order>, whose serialization graph the context registers.[GeneratedContextImport<TContext>]— imports the roots and registrations supplied by another generated context.AddGeneratedContext(context)— registers a context onIServiceCollectionorISerializerBuilder.[GenerateSerializer]remains the separate annotation on a model. The context covers closed serialization graphs, and the name leaves room for generic grain and method types. None of these APIs has shipped (the context feature postdates v10.4.2), so the earlierSerializerContext/AddSerializerContextand context attribute names are renamed directly. The generated public API surfaces are regenerated, and normal Release package validation against the configured 10.4.0 baseline passes without suppressions.A library generates its context beside its models. A consumer imports that context and generates a local envelope or collection graph containing those external roots using a normal ProjectReference and genuine reference metadata. The producer's compiled context supplies complete factories, private selection/copy policy, aliases and dependencies. Its declared roots are opaque provided endpoints, so the consumer does not reconstruct private codec/copier state.
Generated configuration invokes imported contexts through the existing
IConfigureOptionscontract before adding local registrations. Existing provider-key deduplication configures shared imports once. Import graphs are acyclic so each root has one owning context; ORLEANS0115 reports import cycles, invalid context construction/declarations, missing exact closed roots, and exceeded traversal limits. Model/list/array dependency cycles use existing statically closed holders across opaque import boundaries. No runtime tracking is added.The attributes live in serialization abstractions without a dependency on the concrete runtime context; the generator validates the context type, construction and visibility, including friend/internal access. Existing serialized IDs/aliases, wire layouts, constructor order, selected service roles and graph behavior are preserved. Ordinary local serializers retain their public concrete service fields and resolve them through imported producer factories.
Standard metadata inputs
Every added AssemblyMetadata payload/certificate/parser/index and consumer ReferencePath override is removed. The original
ProduceReferenceAssembly=falsesettings are preserved for TestSerializerExternalModels and TestFSharp, which expose complete raw/private/record metadata for external serializer generation. The SDK supplies their implementations through ordinary ProjectReference inputs.All consumer/raw fixture project files match the main baseline. Ordinary production projects produce reference assemblies. An external graph without a supplying context uses full generated metadata; the preferred pattern declares that exact closed graph in its owning assembly and imports the context. A context supplies the closed roots its producer declares.
Current validation
The GeneratedContext rename (
4fc491f) uses SDK 11.0.100-rc.3.26522.148 and bounded MSBuild parallelism:TypeConverterTestspass (69).Earlier distinct-import validation also established source/full/genuine REF local envelope graphs, hidden field-target IDs/Immutable policy, import-only/partial discovery, transitive ownership, shared/diamond imports, same-root cyclic-import diagnostics, model cycles, constructor/IVT/exact generic roots, exact traversal boundaries, normal compiler reference inputs and body/API/Id invalidation. Those semantic proofs are dated to that tested revision; the rename changes names only.
Raw F# 18-per-framework and generated/record/bitwise 105/108 runtime gates remain historical policy evidence. Raw F# model fixtures emit no refs; their current boundary tests use full model metadata and full/reference C# services. No elapsed-speedup claim or new benchmark matrix.
Microsoft Reviewers: Open in CodeFlow