SPECIFICATION.md is authoritative. Accepted entries here are non-semantic implementation decisions unless explicitly stated otherwise.
- Date: 2026-06-17
- Milestone: 1
- Status: Accepted
- Context: The specification requires exact project names and both solution formats.
- Decision: Use SDK-style projects under the exact section 4.6 paths and generate
Mammoth.LiteMapper.slnxfromMammoth.LiteMapper.slnwithdotnet sln Mammoth.LiteMapper.sln migrate. - Specification references: 4.6, 25.
- Consequences:
.slnremains the editable source solution;.slnxis regenerated after solution membership changes.
- Date: 2026-06-17
- Milestone: 1
- Status: Accepted
- Context: The skeleton needs repeatable dependency versions and deterministic project settings.
- Decision: Use central package management in
Directory.Packages.propsand shared deterministic defaults inDirectory.Build.props. - Specification references: 3.4, 4.1, 4.2, 22.1, 22.7, 24.6.
- Consequences: Package versions are controlled centrally; shipping assemblies target
netstandard2.0.
- Date: 2026-06-17
- Milestone: 1
- Status: Accepted
- Context: Milestone 1 must compile without implementing Milestone 2 public abstractions or Milestone 3 generator behavior.
- Decision: Shipping assemblies contain internal marker types only. No public mapping or abstraction API is introduced.
- Specification references: 4.6, 5, 25.
- Consequences: Public API remains empty until Milestone 2.
- Date: 2026-06-17
- Milestone: 1
- Status: Superseded by DEC-0013
- Context: The generator originally had to use the Roslyn 4.0.1 API baseline.
- Decision: Pin
Microsoft.CodeAnalysis.CSharpto4.0.1in central package management and reference it from the generator withPrivateAssets="all". - Specification references: 4.1, 22.7.
- Consequences: Superseded because the approved minimum requirement is now netstandard2.0 generator output with .NET 8.0+ consumer/compiler support, and the Roslyn baseline has been raised to 4.8.0.
- Date: 2026-06-17
- Milestone: 1
- Status: Accepted
- Context: Milestone 1 requires MSTest with built-in assertions.
- Decision: Use
MSTest.TestFramework4.2.3,MSTest.TestAdapter4.2.3, andMicrosoft.NET.Test.Sdk18.6.0; do not add FluentAssertions, Shouldly, or another assertion library. - Specification references: 22.1.
- Consequences: Tests use only MSTest assertion APIs.
- Date: 2026-06-17
- Milestone: 1
- Status: Accepted
- Context: Milestone 1 requires initial Windows and Linux CI.
- Decision: Add separate GitHub Actions workflows for Windows and Linux that restore, build, test, and list both solution formats.
- Specification references: 22.8, 25.
- Consequences: CI skeleton exists; release, trimming, AOT, package-consumer, and benchmark validation remain later milestones.
- Date: 2026-06-17
- Milestone: 2
- Status: Accepted
- Context: Milestone 2 requires public API baselines and Roslyn public API analyzer use.
- Decision: Reference
Microsoft.CodeAnalysis.PublicApiAnalyzers3.3.4fromMammoth.LiteMapper.AbstractionswithPrivateAssets="all"and maintainPublicAPI.Shipped.txtplusPublicAPI.Unshipped.txtin that project. - Specification references: 22.20, 24.4, 25.2.
- Consequences: API changes are checked at build time without adding a runtime package dependency.
- Date: 2026-06-17
- Milestone: 2
- Status: Accepted
- Context: The specification assigns public abstraction types to the abstractions package and does not require the primary package assembly itself to expose forwarding public types in this milestone.
- Decision: Keep
Mammoth.LiteMapperwith no exported public types during Milestone 2 while it referencesMammoth.LiteMapper.Abstractionsas the normal dependency. - Specification references: 4.1, 5, 25.
- Consequences: Consumers get the public API through the dependency; package-consumer behavior remains a later validation milestone.
- Date: 2026-06-17
- Milestone: 2
- Status: Accepted
- Context: Section 22.20 requires package-level API compatibility validation.
- Decision: Use
Microsoft.DotNet.ApiCompat.Tool10.0.301as a temporary validation tool and runapicompat package --run-api-compatagainst the Milestone 2 packages. - Specification references: 22.20, 24.4.
- Consequences: Package API compatibility is validated without adding tool binaries or package outputs to the repository.
- Date: 2026-06-17
- Milestone: 3
- Status: Superseded by DEC-0013
- Context: Milestone 3 required Roslyn source-generator test infrastructure while the generator was still constrained to the Roslyn 4.0.1 API baseline.
- Decision: Use the available official
Microsoft.CodeAnalysis.CSharp.SourceGenerators.Testing.MSTest1.1.2package and a custom Roslyn compilation harness for generator execution, diagnostics, deterministic source inspection, and baseline-compatible incremental checks. - Specification references: 19.1, 21, 22.2, 22.7.
- Consequences: Superseded because the approved Roslyn baseline is now 4.8.0.
- Date: 2026-06-17
- Milestone: 3
- Status: Accepted
- Context: Milestone 3 must establish source emission infrastructure without implementing flat mapping behavior assigned to Milestone 4.
- Decision: Generate one deterministic declaration-only partial source file per valid mapper and intentionally omit mapping method bodies until Milestone 4.
- Specification references: 19.5, 19.7, 19.8, 25.
- Consequences: Generated source can be inspected for deterministic layout, namespace, nesting, and hint names without introducing mapping semantics early.
- Date: 2026-06-17
- Milestone: 3
- Status: Accepted
- Context: The approved support floor is a
netstandard2.0generator assembly and .NET 8.0 minimum consumer/compiler requirements. Roslyn 4.0.1 prevented required observable tracked incremental-step validation. - Decision: Raise the generator compile-time Roslyn baseline from 4.0.1 to 4.8.0 and update
SPECIFICATION.md, central package management, tests, and status to match. - Specification references: 4.1, 22.7.
- Consequences: The generator remains
netstandard2.0, can use Roslyn 4.8.0 APIs, and Milestone 3 can satisfy tracked incremental generator validation without the previous 4.0.1 blocker.
- Date: 2026-06-17
- Milestone: 4
- Status: Accepted
- Context: Milestone 4 introduces configurable unmapped-member diagnostics while the shared diagnostic catalogue uses stable IDs and default severities.
- Decision: Represent policy-specific unmapped-member severities with paired internal
DiagnosticDescriptorinstances that share the same stable diagnostic ID and message but differ by default severity. - Specification references: 6.2, 9.1, 20.1, 20.2.
- Consequences: Generated output is suppressed when an effective policy is
Error; future diagnostics work should verify editorconfig severity override behavior for configurable diagnostics.
- Date: 2026-06-17
- Milestone: 5
- Status: Accepted
- Context: Milestone 5 requires
initproperty support while Milestone 4 emitted ordinary post-construction assignments for flat mappings. - Decision: Render new-object member assignments through object initializers for both
initproperties and ordinary settable members. - Specification references: 10.5, 19.7, 25.
- Consequences: Generated source remains deterministic and direct; the representative Milestone 4 snapshot was updated to the new construction shape.
- Date: 2026-06-17
- Milestone: 6
- Status: Accepted
- Context: Section 11.3 forbids selecting arbitrary compatible helper methods solely by signature while section 11.1 includes local converters and mapping methods in the resolution chain.
- Decision: For Milestone 6, local member conversion is limited to explicit
MapProperty.Use, local[MappingConverter]methods, and localMap{TargetMember}methods. Unmarked local helper methods are not selected by signature. Registered external types may contribute converter or mapping methods because registration is explicit user intent. - Specification references: 11.1, 11.3, 11.4, 11.5, 28.4.
- Consequences: Local helper methods remain ordinary C# unless explicitly named or marked; future nested/default mapping work can add mapping-method/default resolution without introducing arbitrary local helper selection.
- Date: 2026-06-17
- Milestone: 7
- Status: Accepted
- Context: Milestone 7 nullable behavior must be implemented without starting collection mapping or existing-target patch mapping, which are later milestones.
- Decision: Apply nullable mismatch
ErrorandThrowbehavior to mapping shapes already implemented through Milestone 6. Defer collection null materialization andIgnoreNullSourceMemberspatch behavior until the milestones that introduce those mapping forms. - Specification references: 6.3, 12.4, 12.5, 15.11, 16.3, 25.
- Consequences: Null-collection and patch-null tests remain documented as later-milestone validation even though their configuration APIs already exist.
- Date: 2026-06-17
- Milestone: 8
- Status: Accepted
- Context: Section 14 requires private closed-type structural nested helpers, while section 24.4 states exact generated helper organization and local names are not public API.
- Decision: Emit deterministic private helper methods named from the closed source and destination type names, and treat the names as generated implementation details only.
- Specification references: 14.1, 14.2, 19.7, 24.4.
- Consequences: Generated source is deterministic and reviewable; future generator refactoring may rename helpers without changing public API.
- Date: 2026-06-17
- Milestone: 8
- Status: Accepted
- Context: Section 14.1 requires reuse of a visible explicit or default mapping before automatic structural nested mapping, and DEC-0016 previously avoided arbitrary local helper selection for scalar conversion.
- Decision: For nested structural type pairs only, consider compatible visible local mapping methods as default mappings before generating a structural helper; equal-precedence multiple compatible methods report
LITEMAPPER3001. - Specification references: 11.1, 14.1, 20.4, 28.4.
- Consequences: Nested mapping honors the specified precedence without extending arbitrary local helper selection to scalar conversions.
- Date: 2026-06-17
- Milestone: Cross-cutting validation
- Status: Accepted
- Context: Linux builds reported
RS0016for public abstraction types becauseMicrosoft.CodeAnalysis.PublicApiAnalyzersonly auto-includes files namedPublicAPI.Shipped.txtandPublicAPI.Unshipped.txt; the repository usedPublicApi.*, which worked only on case-insensitive filesystems. - Decision: Rename public API baseline files and specification/test references to the analyzer-required
PublicAPI.*casing. - Specification references: 22.20.
- Consequences: Public API analyzer baselines are loaded consistently on Windows and Linux.
- Date: 2026-06-17
- Milestone: 9
- Status: Accepted
- Context: Milestone 9 collection mappings require generated loops and private collection helpers while exact helper organization is not public API.
- Decision: Represent collection mappings as mapping models with deterministic custom loop bodies, reusing the existing helper rendering and nested helper graph instead of adding a separate public or runtime collection mapper abstraction.
- Specification references: 3.2, 15.2, 19.7, 24.4.
- Consequences: Generated collection helpers remain private implementation details; no undocumented public API or runtime registry is introduced.
- Date: 2026-06-17
- Milestone: 9
- Status: Accepted
- Context: Section 15.6 recommends capacity preallocation only when count is cheaply available and section 15.5 forbids counting arbitrary enumerables.
- Decision: Use direct
CountorLengthonly for arrays and known count-bearing collection shapes; custom enumerable sources are enumerated once into a temporary list when an array target requires a final length. - Specification references: 15.5, 15.6, 28.5.
- Consequences:
IEnumerable<T>sources do not receive speculativeCount()calls; array targets from non-count sources allocate a temporaryList<T>beforeToArray().
- Date: 2026-06-18
- Milestone: 10
- Status: Accepted
- Context: Existing-target mappings need direct mutation behavior without adding runtime mapper abstractions or public APIs.
- Decision: Reuse the existing member matching, conversion, helper, and deterministic rendering model for update methods, then render direct destination assignments with optional patch guards instead of introducing a separate runtime update pipeline.
- Specification references: 3.2, 16.1, 16.3, 19.7, 24.4.
- Consequences: Update generated source remains private/direct and shares helper generation with new-object mappings; exact update local formatting is not public API.
- Date: 2026-06-18
- Milestone: 11
- Status: Accepted
- Context: Enum mappings need direct generated behavior without adding runtime mapper abstractions, registries, or reflection.
- Decision: Integrate enum handling into the existing conversion resolver and emit direct switch expressions or checked/unchecked casts. For
[Flags]by-name runtime composites, emit direct bit-test reconstruction over mapped atomic flags. - Specification references: 13, 19.7, 24.1, 28.4.
- Consequences: Enum mapping remains deterministic generated source and private implementation detail; generated flags composite validation uses
System.Convert.ToUInt64and ordinary bit operations rather than runtime reflection or dynamic dispatch.
- Date: 2026-06-18
- Milestone: 12
- Status: Accepted
- Context: Section 17.6 allows either a private mapper-specific tracker helper or an internal shared runtime helper.
- Decision: Emit a private mapper-specific cycle tracker and private reference-identity comparer only when a public mapping has a recursive helper component and effective
ReferenceHandling.ThrowOnCycle. - Specification references: 17.2, 17.3, 17.5, 17.6, 28.6, 28.7.
- Consequences: No public API or shared runtime helper is added; generated source remains deterministic and non-recursive mappings do not allocate tracker state.
- Date: 2026-06-18
- Milestone: 12
- Status: Accepted
- Context: A self-recursive member conversion could select the public generated mapping method as a visible mapping, which would create a fresh public entry call for each descent.
- Decision: Do not select the current generated partial method as its own nested visible mapping candidate; use the private structural helper path so recursive calls can share one tracker.
- Specification references: 17.2, 28.6, 28.7.
- Consequences: Other visible mapping methods remain eligible; self-recursive generated mappings use private helper plumbing for correct active-path tracking.
- Date: 2026-06-18
- Milestone: 13
- Status: Accepted
- Context: Section 21.3 defines development analyzer options and section 3.5 requires framework API capability detection by symbols and exact signatures.
- Decision: Consume the documented analyzer options as global build properties, make them part of source-output invalidation, and gate optimized empty-array emission on finding
System.Array.Empty<T>()by Roslyn symbol signature. - Specification references: 3.5, 19.4, 19.9, 21.3, 21.4.
- Consequences: Option comments/debug metadata do not alter mapping semantics, internal generator failures can be rethrown for development when explicitly enabled, and generated empty-array code falls back to
new T[0]if the API is not present.
- Date: 2026-06-18
- Milestone: 14
- Status: Accepted
- Context: The primary package must be the normal one-package installation route and must make the generator available as an analyzer without making the generator or Roslyn assemblies runtime dependencies.
- Decision: Pack
Mammoth.LiteMapper.Generator.dllexplicitly underanalyzers/dotnet/csin bothMammoth.LiteMapperandMammoth.LiteMapper.Generator; keep the source-tree project reference to the generator as an analyzer withReferenceOutputAssembly="false"andPrivateAssets="all". - Specification references: 4.1, 22.19, 24.1.
- Consequences: Package consumers get generated implementations from one
Mammoth.LiteMapperpackage reference; generator and Roslyn assemblies are absent from consumer runtime output.
- Date: 2026-06-18
- Milestone: 14
- Status: Accepted
- Context: Package-consumer publish validation exercises the supported install shape, while project-reference sample publishing propagates trimming/AOT publish properties into netstandard library projects and fails before reaching LiteMapper-generated code.
- Decision: Use local-feed package-consumer tests as the authoritative trimming and Native AOT validation path. Cover static mapping, instance mapping, nested collections, and cycle detection in that package consumer. Keep the Basic source-tree sample as a runtime sample with a direct analyzer project reference for normal build/run validation.
- Specification references: 22.18, 22.19, 24.1.
- Consequences: Trimmed package-consumer publish and run are validated locally. Native AOT publish and run are validated in Linux with clang/zlib prerequisites; CI sets
LITEMAPPER_REQUIRE_NATIVE_AOT=1so missing Native AOT prerequisites fail instead of producing an inconclusive local result.
- Date: 2026-06-18
- Milestone: 14
- Status: Accepted
- Context: NuGet package archives include generated metadata entries whose names vary between packs, while LiteMapper's owned package payload must remain deterministic.
- Decision: Deterministic package tests compare owned package payload entries under
lib/,analyzers/, and.nuspeccontent shape instead of NuGet-generated metadata filenames. - Specification references: 24.6.
- Consequences: Tests validate deterministic LiteMapper package payload without failing on NuGet's generated package metadata identifier.
- Date: 2026-06-18
- Milestone: 15
- Status: Accepted
- Context: Section 23 requires benchmark comparisons against pinned manual, LiteMapper, Mapperly, Mapster, and AutoMapper implementations; section 26 requires samples to compile and remain the future source for usage documentation.
- Decision: Keep samples as source-tree project-reference executables for development validation, and pin benchmark package versions centrally: BenchmarkDotNet 0.15.8, AutoMapper 16.1.1, Mapster 7.4.0, and Riok.Mapperly 4.3.1. Use a BenchmarkDotNet dry run as smoke validation and reserve controlled benchmark interpretation for release benchmarking.
- Specification references: 23.1, 23.4, 26.
- Consequences: Milestone 15 validates benchmark wiring without fragile throughput thresholds on a shared/local runner; benchmark result output records runtime, SDK, CPU, OS, library versions, and job configuration.
- Date: 2026-06-18
- Milestone: 16
- Status: Accepted
- Context: Section 26 requires usage documentation to be assembled from compiling sample projects and not become a parallel specification.
- Decision: Maintain
docs/USAGE.mdas a checked-in source-backed guide that directly references the compiling Basic, Collections, and ASP.NET Core sample source files, and validate the guide with a packaging test that runs those samples and checks documented snippets, diagnostics, deferred features, and absent runtime-dispatch API claims. - Specification references: 26, 29, 30.
- Consequences: Documentation remains reviewable in source control while CI guards against documenting APIs not represented by compiling samples.
- Date: 2026-06-22
- Milestone: Post-1.0 specification update
- Status: Accepted
- Context: Non-null root source parameters previously always emitted a runtime
ArgumentNullExceptionguard. The project wants an opt-in guard so hot mapping paths can avoid the branch when callers already satisfy the declared non-null contract. - Decision: Add
GuardNonNullSourceas a mapper-levelbooland method-levelOptionState. The library default is disabled. When enabled, generated code rejects runtime null root source values withArgumentNullException; when disabled, no root-source runtime null guard is emitted solely because the source parameter is non-null. - Specification references: 5.2, 5.3, 12.5, 22.11, 28.1.
- Consequences: Public abstractions, API baselines, generator configuration resolution, nullability tests, generated-source snapshots, usage documentation, and package API compatibility validation must be updated before implementation can be considered synchronized with the specification.
- Date: 2026-06-17
- Milestone: 3
- Status: Resolved by DEC-0013
- Context: Section 19.2 requires incrementality to be tested through observable tracked generator steps, but section 22.7 requires the generator baseline to remain Roslyn 4.0.1. The newer public tracked-step inspection APIs used by current Roslyn tests are not available in the Roslyn 4.0.1 API surface used by this milestone.
- Question: Should Milestone 3 raise the test harness Roslyn API level for tracked-step inspection only, define an approved custom observable tracking mechanism, or defer tracked-step inspection until a later approved Roslyn baseline?
- Specification references: 19.2, 21.4, 22.2, 22.7.
- Consequences: User approved raising the generator compile-time Roslyn baseline to 4.8.0; Milestone 3 may proceed with Roslyn tracked incremental-step validation.
- Date: 2026-06-17
- Milestone: 1
- Status: Rejected
- Context: Public marker APIs could make test code easier to write.
- Decision or question: Do not expose public marker types in shipping assemblies during Milestone 1.
- Specification references: 3.2, 5, 25.
- Consequences: Tests load assemblies by name and validate that no public mapping API exists yet.
None.