You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Code style, formatting and the ordering of types/type members should be enforced and fixed
automatically, so that none of the three ever needs a human decision or a review comment again.
Scope is the whole repository: src/, tests/ and benchmarks/. Today only src/ has an
analyzer gate, and ordering is not enforced anywhere.
Decisions
C# keywords, not BCL type names — string, int, bool, not String, Int32, Boolean.
This reverses the current rule and touches 218 of 283 .cs files.
this. prefix stays. No _camelCase for fields or anything else. This becomes enforced
rather than convention. Primary constructor parameters are accessed without this. — they are
parameters in C#, not instance members, so the rule does not apply to them.
Expression-bodied members wherever possible (already the rule, stays).
Primary constructors wherever possible. Currently broken: .editorconfig asks for them via csharp_style_prefer_primary_constructors but disables IDE0290, which is that same rule.
About 37 files have the classic "assign every parameter to a field" constructor.
Member order is StyleCop's order (SA1201/SA1202/SA1203/SA1204/SA1214), plus alphabetical
sorting inside each group.
Architecture — three concerns, three tools, no overlap
Concern
Tool
Config
Formatting (whitespace, line breaks, wrapping)
CSharpier
.editorconfig / .csharpierrc
Code style (semantic)
Roslyn analyzers (current set)
.editorconfig
Ordering — fixing
ReSharper file layout
DbConnectionPlus.slnx.DotSettings
Ordering — checking
NewStyleCop.Analyzers
stylecop.json
Each tool owns its concern completely and is switched off inside the others'.
Why NewStyleCop.Analyzers and not StyleCop.Analyzers: upstream's last release is 1.2.0-beta.556 from December 2023 and predates the C# syntax this repo writes. The fork is at 1.2.1 (stable, 2025-11-29) with 1.3.0-alpha.2 from 2026-08-21, and explicitly added C# 14
extension declarations, collection expressions in SA1413/SA1137, and Roslyn 5.0.0. Same diagnostic
IDs and same stylecop.json, so switching back later is a one-line package change. The risk is
bus factor — a single maintainer — which the one-line exit cost makes acceptable.
Neither package can fix ordering. In both, ElementOrderCodeFixProvider carries [NoCodeFix("Disabled until stable")] and has no [ExportCodeFixProvider], so Roslyn never
registers it. StyleCop detects, ReSharper fixes. That split is deliberate, not a workaround.
Where each tool runs
When
Runs
Tool
AI agent edits a .cs file (PostToolUse hook)
format
csharpier format <file>
Rider save
format
CSharpier plugin, "Run on Save"
Rider Code Cleanup
reorder
ReSharper file layout profile
scripts/tidy-cs.ps1
style fixes → format
dotnet format style → csharpier
scripts/tidy-cs.ps1 -All / preflight.ps1
+ reorder
jb cleanupcode, reorder-only profile
Build (all projects)
style + ordering violations
Roslyn analyzers + NewStyleCop
CI lint job
verify all three
csharpier check; dotnet format --verify-no-changes; cleanupcode + git diff --exit-code
AI agents must run formatting, styling and reordering before every commit. preflight.ps1 is the
single entry point for that.
Work items
1. .editorconfig cleanup
Add root = true — without it, editors keep searching parent directories outside the repo.
Add a [*] section: charset, indent_style, insert_final_newline, trim_trailing_whitespace.
Add sections for [*.{csproj,props,targets}] (tabs), [*.{json,yml,yaml}], [*.md].
Remove the UTF-8 BOM from .editorconfig itself.
Group related settings, order them meaningfully, add explaining comments.
dotnet_style_qualification_for_field/property/method/event → true:error. These are not
set at all today, so this. is currently convention-only.
Remove the IDE0290 suppression so primary constructors are actually enforced.
dotnet_diagnostic.IDE0055.severity = none — conflicts with CSharpier.
Disable the StyleCop rules that conflict with or duplicate CSharpier
(SA1000-SA1028, SA1102-SA1118, SA1127-SA1137, SA1413, SA1500-SA1518 range — see CSharpier's
"Integrating with Linters" doc for the exact list).
Enable the StyleCop rules we actually want: the ordering rules, plus SA1101 (this. prefix)
and SA1309 (no _ field prefix), which match our decisions.
Re-check RCS1037 (trailing whitespace), currently none.
Do not set end_of_line for .cs — .gitattributes owns line endings, and a fixed value
would fight it on Windows. CSharpier's endOfLine: auto default is correct here.
2. Analyzers for tests and benchmarks
Extend the analyzer and style gate to tests/ and benchmarks/, which set neither EnforceCodeStyleInBuild nor TreatWarningsAsErrors today.
Decide per rule what does not apply there (e.g. the XML documentation rules — the
benchmarks already switch RCS1181 off for that reason).
3. CSharpier
Add csharpier to .config/dotnet-tools.json.
Add .csharpierignore; confirm max_line_length = 120 is picked up from .editorconfig
so there is one source of truth for the line width.
Add CSharpier.MsBuild so an unformatted file breaks the build.
Replace dotnet format whitespace with csharpier check in the CI lint job.
Rider: CSharpier plugin, "Run on Save".
4. Ordering
Rename DbConnectionPlus.sln.DotSettings → DbConnectionPlus.slnx.DotSettings. The current
name is almost certainly not loaded at all, because the solution is .slnx. Symptom to
check: Rider still flags the spell-check exceptions in that file as typos.
Define the ReSharper file layout: StyleCop order, alphabetical inside each group.
Create a reorder-only cleanup profile. ReSharper's own reformatting must stay off —
that is CSharpier's job.
Add JetBrains.ReSharper.GlobalTools to .config/dotnet-tools.json.
Add NewStyleCop.Analyzers with a stylecop.json whose elementOrder matches the
ReSharper layout. PrivateAssets=all, like the other analyzer packages.
CI: cleanupcode + git diff --exit-code.
5. Branch naming — adopt Conventional Branch
Adopt Conventional Branch as the repository's branch
naming convention. It is the natural counterpart to the Conventional Commits this repo
already uses, and it covers cases the current rule does not — this issue itself is neither a
feature nor a bugfix.
Replace the rule in CONTRIBUTING.md:10, which currently allows only feature/<issue#>-<slug> and bugfix/<issue#>-<slug>, with the Conventional Branch format <type>/<description> and the ticket-number form <type>/issue-<issue#>-<slug>.
Document the allowed types: feature/, bugfix/, hotfix/, release/, chore/.
Document the AI agent prefixes claude/ and codex/ (the spec also lists ai/, copilot/, cursor/) and decide when an agent should use them instead of a purpose
prefix. This repo is agent-heavy, so the answer should be explicit rather than implied.
Document the character rules: lowercase a-z, digits, hyphens as word separators; no
underscores, spaces or special characters; no consecutive hyphens and none at the start or
end of a description.
Mention it in AGENTS.md too, so Claude Code and Codex pick the right prefix without being
told each time.
6. Documentation and scripts
Rename scripts/format-cs.ps1 → scripts/tidy-cs.ps1; it now does style, formatting and
ordering. Add a -Check mode for CI and an -All scope.
Update both hook wrappers (.claude/hooks/, .codex/hooks/).
Write the member order into AGENTS.md in plain prose, so agents place new members
correctly in the first place instead of relying on the fixer.
Document in AGENTS.md that primary constructor parameters are accessed without this.,
and that this is not an exception to the this. rule — they are parameters in C#, not
instance members.
7. The four mechanical commits
Each rewrites lines across most of the repository without changing meaning. Keep them separate,
in this order, with the full unit suite after each one. Each uses a different tool, so a bad
result is reverted on its own instead of being untangled from the others.
1. String → string and friends — dotnet format style (IDE0049). ~218 files.
2. Convert to primary constructors — dotnet format style (IDE0290). ~37 files.
3. CSharpier reformat — all 283 files.
4. Reorder members — jb cleanupcode, all 283 files.
Add .git-blame-ignore-revs listing all four, and document git config blame.ignoreRevsFile .git-blame-ignore-revs in CONTRIBUTING.md.
GitHub reads the file automatically.
Check PublicAPI.*.txt for churn after commits 1 and 2.
Risks
Field initializer order. Commit 4 moves fields, which changes initialization order and can
change behavior. This is the only part of the four that is not purely cosmetic. Review that diff
for fields whose initializer references another field, and for static readonly chains.
Four whole-repo diffs. Land them while nothing else is open, and run the tests after each.
Alphabetical order inside a group is not checked by StyleCop. Its elementOrder only knows
kind, accessibility, const, static and readonly. Alphabetical sorting is a ReSharper-only
feature. So a member in the wrong alphabetical position is silently fixed by the tidy script and
by Rider, but does not break the build. Accepted.
NewStyleCop.Analyzers has one maintainer. Mitigated by identical rule IDs and config, which
makes switching back to upstream a one-line change.
jb cleanupcode and .slnx: profile lookup was broken and fixed on 2025-12-20
(RSRP-502346). Needs verifying against the current 2026.x tool.
Two tools on save in Rider (CSharpier plugin and ReSharper cleanup) can fight. Mitigation:
on save = formatting only; reordering is a deliberate action plus preflight.ps1.
cleanupcode is slow — it loads and builds the solution, so minutes rather than seconds.
It cannot be a per-edit agent hook; it belongs in the full tidy run, in preflight and in CI.
Goal
Code style, formatting and the ordering of types/type members should be enforced and fixed
automatically, so that none of the three ever needs a human decision or a review comment again.
Scope is the whole repository:
src/,tests/andbenchmarks/. Today onlysrc/has ananalyzer gate, and ordering is not enforced anywhere.
Decisions
string,int,bool, notString,Int32,Boolean.This reverses the current rule and touches 218 of 283
.csfiles.this.prefix stays. No_camelCasefor fields or anything else. This becomes enforcedrather than convention. Primary constructor parameters are accessed without
this.— they areparameters in C#, not instance members, so the rule does not apply to them.
.editorconfigasks for them viacsharp_style_prefer_primary_constructorsbut disablesIDE0290, which is that same rule.About 37 files have the classic "assign every parameter to a field" constructor.
sorting inside each group.
Architecture — three concerns, three tools, no overlap
.editorconfig/.csharpierrc.editorconfigDbConnectionPlus.slnx.DotSettingsstylecop.jsonEach tool owns its concern completely and is switched off inside the others'.
Why
NewStyleCop.Analyzersand notStyleCop.Analyzers: upstream's last release is1.2.0-beta.556from December 2023 and predates the C# syntax this repo writes. The fork is at1.2.1(stable, 2025-11-29) with1.3.0-alpha.2from 2026-08-21, and explicitly added C# 14extension declarations, collection expressions in SA1413/SA1137, and Roslyn 5.0.0. Same diagnostic
IDs and same
stylecop.json, so switching back later is a one-line package change. The risk isbus factor — a single maintainer — which the one-line exit cost makes acceptable.
Neither package can fix ordering. In both,
ElementOrderCodeFixProvidercarries[NoCodeFix("Disabled until stable")]and has no[ExportCodeFixProvider], so Roslyn neverregisters it. StyleCop detects, ReSharper fixes. That split is deliberate, not a workaround.
Where each tool runs
.csfile (PostToolUse hook)csharpier format <file>scripts/tidy-cs.ps1dotnet format style→csharpierscripts/tidy-cs.ps1 -All/preflight.ps1jb cleanupcode, reorder-only profilecsharpier check;dotnet format --verify-no-changes;cleanupcode+git diff --exit-codeAI agents must run formatting, styling and reordering before every commit.
preflight.ps1is thesingle entry point for that.
Work items
1.
.editorconfigcleanuproot = true— without it, editors keep searching parent directories outside the repo.[*]section:charset,indent_style,insert_final_newline,trim_trailing_whitespace.[*.{csproj,props,targets}](tabs),[*.{json,yml,yaml}],[*.md]..editorconfigitself.dotnet_style_predefined_type_for_*→true:error(C# keywords).dotnet_style_qualification_for_field/property/method/event→true:error. These are notset at all today, so
this.is currently convention-only.IDE0290suppression so primary constructors are actually enforced.dotnet_diagnostic.IDE0055.severity = none— conflicts with CSharpier.(SA1000-SA1028, SA1102-SA1118, SA1127-SA1137, SA1413, SA1500-SA1518 range — see CSharpier's
"Integrating with Linters" doc for the exact list).
this.prefix)and SA1309 (no
_field prefix), which match our decisions.RCS1037(trailing whitespace), currentlynone.end_of_linefor.cs—.gitattributesowns line endings, and a fixed valuewould fight it on Windows. CSharpier's
endOfLine: autodefault is correct here.2. Analyzers for tests and benchmarks
tests/andbenchmarks/, which set neitherEnforceCodeStyleInBuildnorTreatWarningsAsErrorstoday.benchmarks already switch
RCS1181off for that reason).3. CSharpier
csharpierto.config/dotnet-tools.json..csharpierignore; confirmmax_line_length = 120is picked up from.editorconfigso there is one source of truth for the line width.
CSharpier.MsBuildso an unformatted file breaks the build.dotnet format whitespacewithcsharpier checkin the CI lint job.4. Ordering
DbConnectionPlus.sln.DotSettings→DbConnectionPlus.slnx.DotSettings. The currentname is almost certainly not loaded at all, because the solution is
.slnx. Symptom tocheck: Rider still flags the spell-check exceptions in that file as typos.
that is CSharpier's job.
JetBrains.ReSharper.GlobalToolsto.config/dotnet-tools.json.NewStyleCop.Analyzerswith astylecop.jsonwhoseelementOrdermatches theReSharper layout.
PrivateAssets=all, like the other analyzer packages.cleanupcode+git diff --exit-code.5. Branch naming — adopt Conventional Branch
naming convention. It is the natural counterpart to the Conventional Commits this repo
already uses, and it covers cases the current rule does not — this issue itself is neither a
feature nor a bugfix.
CONTRIBUTING.md:10, which currently allows onlyfeature/<issue#>-<slug>andbugfix/<issue#>-<slug>, with the Conventional Branch format<type>/<description>and the ticket-number form<type>/issue-<issue#>-<slug>.feature/,bugfix/,hotfix/,release/,chore/.claude/andcodex/(the spec also listsai/,copilot/,cursor/) and decide when an agent should use them instead of a purposeprefix. This repo is agent-heavy, so the answer should be explicit rather than implied.
a-z, digits, hyphens as word separators; nounderscores, spaces or special characters; no consecutive hyphens and none at the start or
end of a description.
AGENTS.mdtoo, so Claude Code and Codex pick the right prefix without beingtold each time.
6. Documentation and scripts
scripts/format-cs.ps1→scripts/tidy-cs.ps1; it now does style, formatting andordering. Add a
-Checkmode for CI and an-Allscope..claude/hooks/,.codex/hooks/).preflight.ps1.AGENTS.md(code style section),CONTRIBUTING.md,.agents/README.md.AGENTS.mdin plain prose, so agents place new memberscorrectly in the first place instead of relying on the fixer.
AGENTS.mdthat primary constructor parameters are accessed withoutthis.,and that this is not an exception to the
this.rule — they are parameters in C#, notinstance members.
7. The four mechanical commits
Each rewrites lines across most of the repository without changing meaning. Keep them separate,
in this order, with the full unit suite after each one. Each uses a different tool, so a bad
result is reverted on its own instead of being untangled from the others.
String→stringand friends —dotnet format style(IDE0049). ~218 files.dotnet format style(IDE0290). ~37 files.jb cleanupcode, all 283 files..git-blame-ignore-revslisting all four, and documentgit config blame.ignoreRevsFile .git-blame-ignore-revsinCONTRIBUTING.md.GitHub reads the file automatically.
PublicAPI.*.txtfor churn after commits 1 and 2.Risks
change behavior. This is the only part of the four that is not purely cosmetic. Review that diff
for fields whose initializer references another field, and for
static readonlychains.elementOrderonly knowskind, accessibility, const, static and readonly. Alphabetical sorting is a ReSharper-only
feature. So a member in the wrong alphabetical position is silently fixed by the tidy script and
by Rider, but does not break the build. Accepted.
makes switching back to upstream a one-line change.
jb cleanupcodeand.slnx: profile lookup was broken and fixed on 2025-12-20(RSRP-502346). Needs verifying against the current 2026.x tool.
on save = formatting only; reordering is a deliberate action plus
preflight.ps1.cleanupcodeis slow — it loads and builds the solution, so minutes rather than seconds.It cannot be a per-edit agent hook; it belongs in the full tidy run, in preflight and in CI.