This repository contains the Purview.ValueObjects package: runtime contracts, an incremental source generator,
a diagnostic analyzer, a code fix, tests, samples, and documentation for scalar and complex value objects.
- This file is the repository-wide source of truth for AI agents. More-specific
AGENTS.mdfiles, if added later, take precedence for their subtrees. - Follow explicit user instructions first, then the nearest applicable repository instructions, then established code patterns.
- Operate only in this repository unless the user explicitly expands the scope.
- Never read, copy, log, or commit secrets from excluded files, environment variables, user profiles, local configuration, test output, or provider credentials.
| Path | Purpose |
|---|---|
src/ValueObjects.slnx |
Canonical solution for restore, build, test, and pack |
src/src/ValueObjects |
Runtime contracts ([Scalar], [ValueObject], IValueObject, ScalarJsonConverterFactory) |
src/src/SourceGenerator |
Roslyn incremental generator and analyzer metadata |
src/src/SourceGenerator.Refactorings |
Code fixes (add partial modifier) |
src/tests |
Unit and source-generator tests, plus the multi-framework Entity Framework Core compatibility project |
samples |
Runnable examples |
docs |
User-facing guidance |
Directory.Packages.props |
Centrally managed NuGet versions |
src/Directory.Build.props / src/Directory.Build.targets |
Solution-wide SDK, package, analyzer, and build behavior |
global.json |
Required .NET SDK and Microsoft.Testing.Platform selection |
package.json |
Authoritative repository/package version |
Justfile |
Supported local workflow commands |
- Read this file, inspect the working tree, and locate the implementation, tests, documentation, and existing patterns relevant to the task.
- Confirm behavior from code and tests rather than relying on memory or documentation alone.
- Make the smallest coherent change. Preserve public behavior unless the task explicitly changes it.
- Update tests for fixes and behavior changes. Update documentation when public behavior changes.
- Run the narrowest meaningful validation first, then broader validation in proportion to risk.
- Review the diff for unrelated edits, generated noise, compatibility risks, and missing docs or tests.
- Keep value objects immutable, validation deterministic, and equality/hash behavior aligned with every value that defines identity.
- Preserve the
Create(strict) /Hydrate(replay-safe) split.OnNormalize/OnValidatehooks are the supported customization points. - Preserve generated API shape:
Create,Hydrate,TryCreate,Empty, comparison, equality, implicit conversions, enum properties, and JSON converters. - Preserve
ValueObjectDeserializationModesemantics (Hydratedefault,Strictre-validates). - Treat
[Scalar]/[ValueObject]/[ValueObjectDefaults], the interfaces, serialized payload shapes, diagnostic IDs, and generated method signatures as compatibility-sensitive contracts. - Scalar value objects serialize as their underlying primitive value; do not change that without a schema/version strategy.
- The generator targets
netstandard2.0; do not use APIs unavailable to that target. - Follow Roslyn incremental-generator practices: derive output from declared inputs, keep transforms deterministic, avoid mutable global state and filesystem/environment dependencies, and make cancellation effective.
- Generated output must be stable for identical input.
- Diagnostics are public developer experience: preserve IDs and meanings, choose accurate locations and severity,
and update
AnalyzerReleases.*.mdfor newly introduced or changed diagnostics. - Cross-component contracts must go through public members. The artifact that consumers (and Visual Studio)
load is the merged, self-contained assembly the
Purview.SourceGeneratorFrameworkmerge pass produces, and that pass strips everyInternalsVisibleTodeclaration. A component that reads another component's internals (for example a code fix reading a diagnostic descriptor) therefore compiles against the unmerged build output and throwsFieldAccessExceptionat runtime in the IDE. Do not addInternalsVisibleTobetween Roslyn components; expose the shared identity publicly (seeDiagnosticLibrary). - Source-generator changes normally require tests in
src/tests/SourceGenerator.UnitTests.
- The runtime targets
net8.0;net9.0;net10.0. Static abstract interface members (IScalarValueObject) require a net7+ floor. ScalarJsonConverterFactoryuses only reflection overScalarAttribute+Create/Hydrate/constructor; keep it free of event-sourcing dependencies.- Keep the runtime package dependency-free (System.Text.Json is in-box for the supported TFMs).
- This repository uses TUnit on Microsoft.Testing.Platform, selected in
global.json. Do not add xUnit, NUnit, MSTest, or FluentAssertions patterns unless explicitly requested. - TUnit test methods use
[Test], and assertion calls are awaited, for exampleawait Assert.That(actual).IsEqualTo(expected);. - Use
--treenode-filterfor test filtering, notdotnet test --filter. - Unit tests should cover domain logic, contracts, failure behavior, and regressions without external infrastructure.
- Entity Framework Core version differences are covered by
src/tests/ValueObjects.EFCompatibility.IntegrationTests, which targetsnet8.0with EF Core 7,net9.0with EF Core 9, andnet10.0with EF Core 10. Add version-dependent behavior there (and, where a synthetic reference set is enough, toSourceGenerator.IntegrationTests) rather than weakening generated output gated onIsEF8Referenced. - Source-generator tests assert generated code and diagnostics using the existing testing framework
(
Purview.SourceGeneratorFramework.Testing.TUnit).
- Keep
README.md, package READMEs, anddocs/aligned with actual supported behavior. - Examples must compile conceptually against current public APIs. Use placeholders for credentials and environment-specific values.
Prefer the Justfile recipes or their equivalent commands:
dotnet tool restore
just restore
just build
just test
just lint-check
just pack
just pipeline-pr
The repository uses the shared Purview.Build pipeline (purview-build.json at the root). just pipeline-pr
installs the pinned Purview.Build tool to .tools/purview-build when missing.
Local CI-equivalent validation:
dotnet restore src/ValueObjects.slnx
dotnet build src/ValueObjects.slnx --no-restore --configuration Release
dotnet test src/ValueObjects.slnx --no-build --configuration Release --ignore-exit-code 8 -- --treenode-filter "/*/*/*/*[Category=Unit]"
dotnet csharpier check .
Use dotnet csharpier check . for validation and dotnet csharpier format . to fix formatting. Pack when package
assets, public package dependencies, analyzers, build targets, or packaging metadata change.
package.jsonis the authoritative release/package version. Do not manually diverge project versions.- Release is automatic on push to
main: theReleaseworkflow runs the sharedPurview.Buildpipeline withRelease:Mode=NuGet, publishing packages and creating thev<version>GitHub release only when that tag does not already exist. - Never create release tags or publish packages manually unless the user explicitly requests a documented recovery procedure.
Before handing work back:
- Confirm the requested behavior and scope are satisfied.
- Confirm only intended files changed.
- Review public API, serialization, and package-content implications.
- Add or update focused tests for code changes.
- Update all affected docs, samples, analyzer metadata, and release notes when applicable.
- Run appropriate build, test, formatting, and pack checks in proportion to risk.
- State exactly what validation ran. If a check was skipped or blocked, give the concrete reason and remaining risk.