Skip to content

Drop the two import keys that wedge dotnet format - #11

Merged
ddfreiling merged 1 commit into
Notalib:mainfrom
henrikottesorensen:fix/dotnet-format-imports-loop
Aug 13, 2026
Merged

Drop the two import keys that wedge dotnet format#11
ddfreiling merged 1 commit into
Notalib:mainfrom
henrikottesorensen:fix/dotnet-format-imports-loop

Conversation

@henrikottesorensen

Copy link
Copy Markdown
Collaborator

The problem

A consuming repository reported that dotnet format would not fix its using order, while the build kept failing on UA1000. Reproduced and measured: as shipped, three consecutive dotnet format runs leave the file byte-identical and dotnet format --verify-no-changes exits 2 every time.

after dotnet format run #1 -> verify EXIT=2  | md5 5cf85de64fb803cfd6e94c406ab9a686
after dotnet format run #2 -> verify EXIT=2  | md5 5cf85de64fb803cfd6e94c406ab9a686
after dotnet format run #3 -> verify EXIT=2  | md5 5cf85de64fb803cfd6e94c406ab9a686

The file on disk is already correct. There is nothing the consumer can do to make CI green.

Cause

dotnet format style runs an organize-imports stage, reported as error IMPORTS: Fix imports ordering. It switches on if and only if dotnet_sort_system_directives_first or dotnet_separate_import_directive_groups is explicitly set — at any value, including false. Isolated each:

setting dotnet format --verify-no-changes
dotnet_sort_system_directives_first = true EXIT=2
dotnet_separate_import_directive_groups = true EXIT=2
dotnet_separate_import_directive_groups = false EXIT=2
both absent EXIT=0

Once armed it sorts flat-alphabetically after System, putting Nota.* above the vendors — the inverse of UA1000's third block. The style stage reorders, the analyzers stage puts it back, the file never changes on disk, and --verify-no-changes reports what the style stage wanted.

The note in the globalconfig reasoned that the per-vendor grouping was "checked by IDE0055 only, which is off here, so nothing reports it". True, and beside the point — the imports stage is not a diagnostic, has no severity, and dotnet_diagnostic.IDE0055.severity = none does not reach it. It checked what reports, not what enforces. Rider is unaffected, which is why this only ever bit whoever formats from the command line.

The change

Both keys removed from content/Nota.CodeAnalysis.globalconfig, with a comment recording why they must stay absent rather than be set to false.

What it costs, measured

SA1516 does lose one check. With UA silenced, on usings with no blank line after the System group:

dotnet_separate_import_directive_groups = ABSENT -> SA1516 hits: 0
dotnet_separate_import_directive_groups = true   -> SA1516 hits: 2
dotnet_separate_import_directive_groups = false  -> SA1516 hits: 0

UA1001 already requires that blank line, and knows first party from vendor where SA1516 only ever saw first-level namespaces. What goes is the blunter duplicate of a check we still have.

Verification

Removing the key broke verify.sh, which asserted SA1516 for exactly that blank line — the suite doing its job:

Verification failed:
  - SA1516 did not report - it is configured but not reaching consumers

Samples/Unseparated.cs now carries both faults: using blocks in the right order with no blank line between them (UA1001), and two members with no blank line between them (SA1516, on its own turf). Its members carry no doc comments deliberately — a comment between them is reported by SA1514 instead, and SA1600 is off here.

All three scripts pass:

verify.sh:             All 7 rules reported.
verify-encoding.sh:    All source files are valid UTF-8 or BOM-marked UTF-16.
verify-package.sh:     All rules survive packaging.

End to end against the reporting consumer's own two .editorconfig files: one dotnet format pass produces the canonical layout and --verify-no-changes exits 0 repeatedly.

Note for consumers

An .editorconfig entry beats a global analyzer config entry, so a consumer can re-arm this from their own repository. Both READMEs now say not to set either key, not even to false.

Interim workaround

Until this ships, a consumer on the current package can skip the style stage — verified against the published config:

dotnet format whitespace && dotnet format analyzers

🤖 Generated with Claude Code

dotnet_sort_system_directives_first and dotnet_separate_import_directive_groups
are gone from the globalconfig. Not set to false - absent. Their presence at any
value arms the organize-imports stage of "dotnet format style", which reports as
"error IMPORTS: Fix imports ordering" and sorts flat-alphabetically after System,
putting Nota above the vendors. That is the inverse of what UA1000 requires.

The result is a loop rather than a wrong file. The style stage reorders, the
analyzers stage puts it back, the file on disk never changes - so dotnet format
reports nothing to do while dotnet format --verify-no-changes exits 2 forever,
and a consuming repository cannot make CI green by any means available to it.

The old note here reasoned that the per-vendor grouping was "checked by IDE0055
only, which is off here, so nothing reports it". That is true and beside the
point: the imports stage is not a diagnostic, has no severity, and setting
dotnet_diagnostic.IDE0055.severity = none does not reach it. It checked what
reports, not what enforces. Rider is unaffected, which is why this only ever
showed up for whoever formats from the command line.

Measured against a real consumer with both of its .editorconfig files, not
reasoned about: as shipped, three consecutive runs left the file byte-identical
and --verify-no-changes exited 2 every time; with the keys removed, one pass
produces the canonical layout and it exits 0.

verify.sh asserted SA1516 for the blank line after the System group, and that
only worked because the key was set - so removing it broke the suite, which is
the suite doing its job. UA1001 makes that check now, and knows first party from
vendor where SA1516 only ever saw first-level namespaces. Samples/Unseparated.cs
carries both faults so SA1516 stays asserted on member separation, which was
always its own job.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@ddfreiling ddfreiling left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😆

@ddfreiling
ddfreiling merged commit 1301680 into Notalib:main Aug 13, 2026
1 check passed
henrikottesorensen pushed a commit that referenced this pull request Aug 13, 2026
0.4.0 adds UA1002, which reports the settings that make something else rewrite
the using block. This package spent two releases getting that wrong by hand: the
globalconfig carried dotnet_sort_system_directives_first and
dotnet_separate_import_directive_groups with a comment explaining why they were
harmless, and they were not - they wedged dotnet format for every consumer who
formatted from a command line, and it took a downstream repository losing a day
to find out. #11 removed them. This is the part that stops them coming back.

The keys are gone from here, so UA1002 is silent in this repository, and silence
is exactly what a rule that never arrived looks like - which is the failure mode
this repository exists to be paranoid about. So it was checked rather than
assumed: adding dotnet_separate_import_directive_groups = false to the
verification project reports UA1002 through the installed package, and removing
it again returns to nothing reported.

Consumers get a new warning for configuration they already had, which is the
point and is still a behaviour change. Anyone who set either key in their own
.editorconfig - an .editorconfig entry beats this globalconfig, so that override
was always available - will see UA1002, and under TreatWarningsAsErrors their
build stops. Their build was already broken in the way that mattered; only
dotnet format knew. That makes this a minor release rather than a patch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants