Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,29 @@

## Unreleased

## Fixes
The following changes are not included in the published `3.0.0` package. No next release version is assigned here.

### Breaking Changes

These are conditional source/runtime compatibility changes from `3.0.0`, even though public package API compatibility checks pass. They correct unintended behavior and affect consumers using the described shapes; they are not universal API removals.

- **Ambiguous name matching (#28):** `IgnoreCase` mappings that previously selected an exact member from multiple case-insensitive matches now fail with `LITEMAPPER1004`. Select the intended source with `MapProperty.Source`, or use `Exact`/`ExactThenIgnoreCase` when exact-name priority is intended.
- **Collection equality (#31, #51):** dictionary value-only conversion now preserves a compatible source key comparer; custom key or set-element conversion uses the destination default comparer. Lookups, duplicate-key exceptions, set membership, and element counts can change. Recheck equality-sensitive mappings and collision expectations after upgrading.
- **Per-entry policies (#21):** mappings sharing model pairs now consistently honor each entry's numeric, enum, null, and cycle policies. Previously masked nullable/null-collection errors can surface as `LITEMAPPER2001` or `LITEMAPPER2002`; checked/unchecked, by-name/by-value, and preserve/empty results can differ. Review each entry's intended policies and satisfy reported nullability obligations instead of relying on another entry's helper behavior.
- **Explicit root-source converters (#23):** omitted-`Source` configuration invokes the root converter even when no matching source member exists and unmapped targets are ignored; a former default value can become the converter result. Patch calls no longer depend on an unrelated same-name nullable member. Recheck converter outputs and patch null behavior; select a source member explicitly when member-based input is intended.
- **Patch getter and overload behavior (#29, #47):** guarded source getters are consumed once, and captured nullable values retain the selected nullable updater overload instead of binding a competing non-nullable overload. Side effects, selected updater results, and exceptions from a second getter read can change. Recheck stateful getters and overloaded updaters; do not rely on a second read or the previously incorrect overload.
- **Null structural elements (#26):** built-in structural collection mapping now preserves null for nullable element targets. For nonnullable element targets under `Throw`, it raises `InvalidOperationException` before constructing the target object or reading source members, rather than dereferencing null in the helper. Higher-precedence nullable converters still receive null. Recheck null handling, side effects, and exception expectations.
- **Enum exception metadata (#27):** nullable-root by-name enum failures now identify the declared input parameter instead of a generated capture name. Update assertions or error handling that inspect `ParamName` or related exception text.

### Fixed

- Issue #51: set mappings use the destination default comparer after custom element conversion, including same-type converters, preventing incorrect collapse of distinct mapped values. Identity-mapped sets retain compatible source comparers. [#51](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/51)
- Issue #48: configured enum paths preserve missing reference intermediates as null for nullable enum destinations, including constructor-bound and existing-target mappings. By-name errors, by-value conversion, single evaluation, patch skipping, and converter precedence are preserved. [#48](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/48)
- Issue #47: configured direct and dotted nullable-value patch captures retain their source type when invoking nested updaters, preserving the selected nullable overload when a competing non-nullable overload exists. [#47](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/47)
- Issue #32: recursive cycle paths retain compact immutable segments and format the full path only when a cycle is detected, removing quadratic path-prefix allocations while preserving exception metadata and first-edge allocation behavior. [#32](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/32)
- Issue #31: dictionary mappings preserve compatible key comparers independently of value conversion. Keys transformed by custom converters use the destination default comparer, even when key types match. [#31](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/31)
- Issue #30: set mappings probe exact accessible HashSet capacity constructors and use portable fallbacks when absent, including on netstandard2.0. Capacity-plus-comparer support is detected independently. [#30](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/30)
- Issue #29: patch-mode nested updaters consume the captured direct source value once, preserving null skips, overload selection, and sequential update behavior. [#29](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/29)
- Issue #28: IgnoreCase rejects multiple case-insensitive source matches even when one is exact; nested structural ambiguity retains LITEMAPPER1004. Exact and ExactThenIgnoreCase keep their existing exact-match priority. [#28](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/28)
- Issue #27: by-name enum exceptions use stable source names and paths instead of applying `nameof` to guarded expressions; nullable enum captures retain source metadata. [#27](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/27)
- Issue #26: structural collection mapping preserves nullable elements and applies Throw guards before object helpers; nullable nested collection helper signatures retain their annotations. [#26](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/26)
Expand Down Expand Up @@ -37,8 +53,6 @@

### Fixed

- Issue #29: patch-mode nested updaters consume the captured direct source value once, preserving null skips, overload selection, and sequential update behavior. [#29](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/29)

- Issue #11: existing-target mappings with `NullableMismatch.Throw` now evaluate and enforce nullable preconditions in deterministic per-member order, preserving earlier assignments when a later member fails. [#11](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/11)
- Issue #12: declared cycle tracking now identifies mappings by symbol identity instead of method name, preventing overload false positives, invalid tracker arguments, and unnecessary tracking state. [#12](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/12)
- Issue #13: direct nullable sources passed to nested updaters are evaluated once, preventing duplicate source getter or path evaluation. [#13](https://github.com/PrimordialCode/Mammoth.LiteMapper/issues/13)
Expand Down
8 changes: 8 additions & 0 deletions IMPLEMENTATION_PLAN.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Mammoth.LiteMapper Implementation Plan

## Consumer documentation release guidance (2026-10-12)

- Scope: correct README/usage installation, analyzer-property exports, consumer-skill guidance, and prominent changelog compatibility warnings. No product source, public API, specification semantics, or package version changes.
- Review correction: describe the current library behavior directly as the release contract in the consumer skill and its reference. Mention previous versions only for breaking-change migration, not ordinary recipes. Use factual package-install commands without claiming an unpublished package is available. Keep the distributable skill self-contained: all document references and links stay within its own folder, with essential consumer guidance bundled locally.
- Validation: preserve the completed published-package quickstart/analyzer/central-management probes, repeat changed-skill format/discovery/install/link checks, including isolated installation and every bundled document target and source-backed usage validation, then verify exact-head Windows/Linux and Roslyn CI. Bind artifact/release evidence to its actual SHA and version rather than carrying it forward as final-head acceptance.
- Release readiness: separately track final-version artifact validation, nonpublishing workflow rehearsal, and administrator-controlled release safeguards. Performance evidence is separate and does not authorize changing its policy.
- Operations: isolated cloud worktree `codex-consumer-release-docs`; AgentStack CLI is absent and the authorized connector fallback omits issue comments/claim writes. Stop at draft PR/human review. No merge, release, tag, package publication, protection changes, or duplicate login request.

## Issue #51: comparer selection after set element conversion (2026-10-12)

- Scope: use the destination default comparer whenever set-element resolution selects a non-identity conversion, including same-type custom converters. Preserve identity comparer reuse, constructor capability selection, collection copying, single enumeration, null policy, and converter precedence. No public API or specification semantics change.
Expand Down
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ Mammoth.LiteMapper is a convention-first, compile-time object mapping library fo

Consumers declare partial mapping methods on classes marked with `[LiteMapper]`. A Roslyn incremental source generator emits direct C# implementations using constructors, assignments, loops, casts, and ordinary method calls. LiteMapper is not a runtime mapping container and does not provide runtime mapper registration, assembly scanning, reflection fallback, or dynamic dispatch.

Assembly-wide defaults and external mapper registrations are compile-time inputs. When they change, the incremental generator reevaluates affected generated mappings and diagnostics while preserving unrelated output where Roslyn can preserve its candidate identity.

Generated nested and collection helpers are private implementation details of each generated mapper. Their names are allocated deterministically within that mapper, reserve handwritten and other generated helper signatures, reuse names for identical closed source/destination pairs with equivalent effective options, nullable shape, and execution context, and disambiguate distinct semantic identities without depending on syntax-tree order. Consumers must not depend on generated helper names or signatures.
Assembly-wide defaults and external mapper registrations are compile-time configuration. Rebuild after changing them. Generated helpers are private; call only the mapping methods you declare and do not depend on helper names or signatures.

## Compilation Status

Expand All @@ -16,12 +14,14 @@ Generated nested and collection helpers are private implementation details of ea

## Quickstart

Install the primary package:
Install the published stable primary package, `3.0.0`, in a project without central package management:

```xml
<PackageReference Include="Mammoth.LiteMapper" />
<PackageReference Include="Mammoth.LiteMapper" Version="3.0.0" />
```

For central package management, put the version in `Directory.Packages.props` instead; see [installation](docs/USAGE.md#installation). The [version notes](docs/USAGE.md#versions-and-upgrading) distinguish `3.0.0` from unreleased fixes in this checkout.

Declare a mapper:

```csharp
Expand Down Expand Up @@ -53,10 +53,10 @@ Ordinary unmapped target members are reported as `LITEMAPPER1001` errors by defa

The [mammoth-litemapper skill](skills/mammoth-litemapper/SKILL.md) provides consumer mapping guidance for compatible coding agents using the [Skills CLI](https://skills.sh/docs).

Once this skill is published on the repository's default branch, install it from your consuming project:
Install the skill from the explicit `develop` branch, which includes guidance for `3.0.0` and clearly marked unreleased corrections:

```sh
npx skills add PrimordialCode/Mammoth.LiteMapper --skill mammoth-litemapper
npx skills add https://github.com/PrimordialCode/Mammoth.LiteMapper/tree/develop/skills/mammoth-litemapper --skill mammoth-litemapper
```

Append `--agent codex` to target Codex or `--global` for user-level installation. To preview this checkout's discoverable skills without installing, run `npx skills add . --list` from the repository root. The skill contains its own supporting reference; consumers do not need a LiteMapper source checkout. Local validation does not establish a skills.sh directory listing.
Append `--agent codex` to target Codex or `--global` for user-level installation. To preview this checkout without installing, run `npx skills add ./skills/mammoth-litemapper --list` from the repository root. The skill includes its supporting reference and needs no source checkout. Installing the skill does not upgrade the NuGet package; verify the package version before using an unreleased correction.
18 changes: 18 additions & 0 deletions STATUS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Mammoth.LiteMapper Status

## Consumer skill review correction (2026-10-12)

- User-directed correction: the consumer skill and mapping reference describe the current library release contract directly. Previous versions appear only in breaking-change migration; normal recipes no longer frame supported behavior as upcoming or unreleased. The package command uses the consumer's configured feed and does not invent an available version. All skill document links and references stay inside its distributable folder; essential guidance is bundled instead of redirecting to repository documentation. This supersedes the initial skill framing in the checkpoint below.
- Scope: skill/reference prose, prominent conditional breaking-change notes in the changelog, and control-document updates only. README/usage installation and analyzer-export corrections remain intact; no library source, test, project/dependency, workflow, specification, or package-version change.
- Correction validation: skill format, cached-CLI discovery, isolated installation, installed-file byte equality, and both bundled document links pass. No external document links or repository/specification/sample redirects remain. The exact `dotnet add package Mammoth.LiteMapper` command resolves 3.0.0 from the existing configured feed; the skill quickstart builds with zero warnings/errors and returns Id=42. Focused usage validation passes 1/1 with zero skips. Final wording-only evidence refinements repeat the format/install/link/content checks; source/sample code is unchanged.
- Prior-head evidence: CI 38234941066 passed at bd7b366, with 1,315 tests each on Windows/Linux and 1,034 in each of six Roslyn jobs, zero failures/skips. Five published-package documentation probes and the earlier skill checks passed. Changed-skill revalidation and the final correction-head CI are recorded in PR #53 rather than represented as evidence for an untested SHA.
- Non-performance release gaps: no additional product-code defect was established. Provisional 3.1.0 artifacts are stamped bd7b366, not this correction; local final-package trimming/AOT failed at MSBuild task-host creation, including the supported trimming retry. Ordinary CI skipped release pack/validation and artifact-handoff jobs. A full nonpublishing rehearsal and selected final-version/ref artifacts remain necessary.
- Safeguards: read-only HTTP 200 checks at 13:52 UTC still found no repository/inherited rulesets and no production required-reviewer rules. The sole secure GitHub login request remains unresolved; no duplicate request or dispatch occurred. Performance evidence is tracked separately; this correction does not rerun benchmarks or declare overall release readiness.
- Boundary: retain draft PR/human review. No merge, tag, release, publication, credential handling, or protection-setting change.

## Consumer documentation release-boundary checkpoint (2026-10-12)

- Scope: documentation only, based on develop f0d4bee in isolated `codex-consumer-release-docs`. Stable `3.0.0` installation remains available; unreleased behavior and upgrade effects are explicit, upstream source links are pinned, central package management is separate, and analyzer options include compiler-visible exports. Changelog #29 is under Unreleased, #47 is included, and #28/#31/#51 have upgrade considerations. No package version, source, public API, or specification semantics changed.
- Consumer validation: five isolated C# 9/net10.0 consumers extracted from the documented snippets restore, build with zero warnings/errors, and execute `Id=42` against the published `3.0.0` packages: standalone, central package management, hidden/visible analyzer properties, and central management with visible analyzer properties. The versionless non-central negative control fails with NU1015. Generated source and analyzer config prove the exports enable both diagnostic comments and expose all three properties.
- Source-backed validation: explicit solution restore and Release packaging-test build pass with zero build warnings/errors. `dotnet test tests/Mammoth.LiteMapper.Packaging.Tests/Mammoth.LiteMapper.Packaging.Tests.csproj -c Release --no-build --no-restore --filter Milestone16UsageDocumentationTests` passes 1/1 with zero skips and runs the Basic, Collections, and ASP.NET Core smoke samples.
- Skill validation: skill-creator `quick_validate.py`, local discovery, isolated Codex installation including the supporting reference, and remote discovery through the documented develop URL pass. Local paths/anchors and pinned source-file links resolve; unchanged content retains its original line endings, and CRLF-aware diff checks pass. Remote discovery validates the available develop skill, not publication of this uncommitted correction.
- Environment and boundary: existing SDK 10.0.401, task-local caches/temporary files, and one-processor builds. AgentStack CLI is absent; authorized connector fallback omits issue comments/claim writes. Final PR-SHA CI, full release validation, and controlled performance evidence remain separately pending. Stop at draft PR/human review; no merge, tag, publication, or workflow dispatch.

## GitHub issue #51 set element comparer checkpoint (2026-10-12)

- Base: isolated cloud worktree from develop f7de4cf28ec63c2c3ac4c812cbdbe16502b2be62. Duplicate searches found no existing issue for the set-conversion defect; #30 and #31 concern separate constructor/dictionary behavior. New issue #51 has no blocked-by dependencies, sub-issues, or competing PR. Authorized exec:agent and ready:agent labels were applied and read back. AgentStack CLI is absent; connector fallback is used without issue comments or claim writes.
Expand Down
Loading