Skip to content

Resolve a command's key where the context values are built - #2434

Merged
woksin merged 4 commits into
mainfrom
fix/command-key-resolution-and-quick-fix
Jul 31, 2026
Merged

Resolve a command's key where the context values are built#2434
woksin merged 4 commits into
mainfrom
fix/command-key-resolution-and-quick-fix

Conversation

@woksin

@woksin woksin commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Follows up the two loose ends left by #2431.

Added

Changed

Deprecated

woksin and others added 4 commits July 31, 2026 01:03
Reading the key from the command was done where the key is read, which
made an extension method reach into the service provider for the rules and
gave a caller without one a different answer. It now happens while the
command context values are being built, next to the providers that resolve
the key in the first place: once per command rather than once per read
model resolved, and the same answer for everything that reads it.

GetResolvedKey() is a lookup again. The overload taking a service provider
shipped in 20.68.0, so it stays and is marked obsolete rather than removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRa2Z1cA6D3Fuw9TAo6m2p
ARCCHR0008 named the attribute to use but read like a typo, when what it
reports is that key resolution has changed underneath the command - so the
message now says what happens if it is left alone, and the report sits on
the attribute rather than the property name.

The fix writes the attribute out in full rather than adding a using: a file
marking the data annotations attribute already imports that namespace, and
with both in scope a bare [Key] is ambiguous. It is annotated for
simplification, so it shortens once the old using goes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRa2Z1cA6D3Fuw9TAo6m2p
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRa2Z1cA6D3Fuw9TAo6m2p
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VRa2Z1cA6D3Fuw9TAo6m2p
@woksin woksin added the minor label Jul 30, 2026
@woksin

woksin commented Jul 30, 2026

Copy link
Copy Markdown
Contributor Author

Addresses the two things I flagged as unsettled on #2431 rather than leaving them as caveats.

Key resolution moved out of the extension method

#2431 read a command's key inside CommandContextExtensions.GetResolvedKey, resolving ICommandKeys from a service provider passed in. That was the deliberate trade-off I called out: the alternative — a second ICommandContextValuesProvider writing the same key — would have left precedence undefined, because CommandContextValuesBuilder merges provider output last-wins over IInstancesOf<> discovery order.

The third option is better than either: resolve the key in the builder, after the providers have run and only if none wrote one. It is a DI service, so nothing is service-located; precedence is a single explicit branch; and it fixes two things beyond the smell:

  • the key is resolved once per command rather than once per read model resolved;
  • everything reading the key sees the same answer — before, a caller with no service provider got null where one with it got a key.

GetResolvedKey() is a lookup again and ReadModelUnresolvableDependencyClassifier no longer passes a provider.

GetResolvedKey(CommandContext, IServiceProvider?) shipped in 20.68.0, so it is [Obsolete] rather than removed — it now delegates, and only matters for a CommandContext assembled without ICommandContextValuesBuilder. Removing it is a major; happy to do that instead if you would rather not carry it.

ARCCHR0008 made actionable

The rule always fired once Chronicle was referenced — the gap was that it read like a typo when what it reports is that key resolution changed underneath commands nobody touched. So the message now names the consequence, the report sits on the attribute rather than the property name, and there is a code fix.

The fix writes [Cratis.Chronicle.Keys.Key] in full rather than adding a using. A file marking the data annotations attribute already imports that namespace, and with both in scope a bare [Key] is CS0104 — so adding a using would trade a silent bug for a build error. It carries Simplifier.Annotation, so it shortens to [Key] once the old using goes, and that is documented on the rule page.

Two supporting changes worth knowing about:

  • Chronicle.CodeAnalysis gains Microsoft.CodeAnalysis.CSharp.Workspaces, which CodeFixProvider needs. That trips RS1038; rather than invent a suppression I mirrored the existing .editorconfig in Arc.Core.CodeAnalysis, comment included, since that project already made the same trade to co-locate fixes with analyzers.
  • The diagnostic location change moved the reported span to the whole [property: Key] application on a positional record, so the marker in the existing analyzer spec moved with it. The code fix therefore locates the attribute from the reported node rather than assuming the node is the attribute, and picks the one named Key rather than the first in the list.

This does not close #2433 — that is about surfacing the change at the moment Chronicle is added, which an analyzer cannot see. It does make the diagnostic that fires afterwards say the right thing and fix itself.

Verification

Clean dotnet build -c Release from the repository root, all three TFMs: 0 errors, 1 warning — the pre-existing CS0436 in TestApps/Chronicle that reproduces on main.

All 15 spec projects green: Arc.Core 1596, Chronicle 563, Chronicle.CodeAnalysis 41, Screenplay 1173, ProxyGenerator 1039, MongoDB 148, EF 300 and the rest. The new and changed specs were also run isolated by filter.

Documentation/verify-markdown.sh passes.

Review

Authored by an agent with no human review.

@woksin
woksin merged commit 66a1761 into main Jul 31, 2026
54 checks passed
@woksin
woksin deleted the fix/command-key-resolution-and-quick-fix branch July 31, 2026 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant