ADR-0022: Optional attributed mapping generation with finalized-model verification¶
Status: locally and hosted verified. Run 38120282034 builds the generator and actual analyzer-only project/package consumers with zero warnings/errors; all 36 diagnostics, incremental-output and finalized/manual-model parity tests pass within 976 successful tests.
GB-016 supplies an optional IIncrementalGenerator and a companion analyzer. The input is an explicitly opted-in static partial registration class listing annotated CLR entity types. Nodes and identified edges declare storage tokens, ordered application keys, property requiredness, supported conversions and concurrency. Edge endpoints name complete ordered FK slots. The generator does not infer arbitrary EF conventions or interpret user OnModelCreating code.
The generator targets netstandard2.0 and references only Roslyn and its framework dependencies. SDK 10.0.401's inspected Roslyn compiler is product 5.9.0-1.26423.113, matching the repository's exact Microsoft.CodeAnalysis.CSharp 5.9.0 package line. A real consumer project references the generator with OutputItemType="Analyzer" and ReferenceOutputAssembly="false"; authoring attributes are emitted into the consumer rather than supplied by a new runtime dependency.
Generated output consists of explicit Apply(ModelBuilder) registration, static graph/IRI identifiers, a canonical expected storage witness and its SHA-256, and Verify(IModel). Apply configures ordinary finalized EF metadata. Verify calls the provider's existing GraphSchemaManifest.Create on the actual model, then compares fingerprints. The caller invokes verification after model finalization; it is not performed while OnModelCreating executes. Complete-model comparison deliberately detects additional mapped entities or omitted registration as well as changed storage facts.
The compile-time expected witness is distinct from the runtime manifest authority. ADR-0019's offline CLI continues to construct its manifest from its actual generated-only finalized EF model. Roslyn cannot perform that execution safely. Instead, the new generator predicts only its closed, explicitly emitted mapping subset. A dependency-free expected-witness writer reproduces schema-version-1 canonical bytes for that subset, while the runtime serializer remains unchanged. Exact generated-versus-finalized-versus-independent-handwritten byte/hash parity is a mandatory gate. No caller can pass this expectation into the runtime binding compiler as a replacement IModel.
Explicit save behaviors and value generation avoid reliance on implicit key-generation conventions. Application keys use ValueGeneratedNever; provider versions use IsRowVersion. Identified edge FK slots remain outside stored relationship properties. The expected witness includes the runtime caveat for conventional indexes over endpoint FK slots and the opaque-converter caveat for DateOnly conversion. Fingerprint equality describes the versioned storage contract, not arbitrary converter behavior, CLR navigation semantics or full behavioral model equivalence.
The first contract supports keyed nodes, identified edges, composite node keys/endpoints, supported scalar conversions, original-value concurrency and long generated versions. Diagnostics locate unresolved endpoints, invalid or duplicated mapping names, missing/incompatible keys, conflicting/nullability metadata and unsupported members. It rejects EF/data-annotation mapping attributes in the generated contract. Alternate keys/indexes, shadow mappings, association edges, native node references, inheritance and custom converter code require future explicit contract work and parity tests; they are not inferred from runtime capabilities.
Dynamic model conventions and later application configuration are outside compilation authority. Such customization remains valid EF authoring, but a storage change invalidates the generated expectation until explicitly reconciled. A generator cannot promise to diagnose arbitrary executable model mutation. Runtime verification remains necessary, and fingerprint caveats remain applicable even when it succeeds.
The implementation uses ForAttributeWithMetadataName, immutable generation results and semantic declarations. Successful equal outputs can be reused after unrelated syntax changes. Diagnostics retain source locations; output sorting and stable names avoid filesystem order and process-dependent hashes. Generator-driver tests cover unchanged/unrelated edits, deterministic source, supported source literals, failures and actual generated compilation. Separate parity tests instantiate finalized contexts with a transport-rejecting driver proxy. All 36 tests pass locally. Roslyn can reevaluate the semantic contract as Unchanged; the test additionally requires the actual source-output steps to be Cached.
M6's remaining restricted-access/Enterprise deployment acceptance and M7 release/benchmark checks remain independent open gates. This optional generator does not waive them or become a prerequisite for ordinary provider use.