Review code style - #340
Conversation
Fix some ReSharper hints. Not all hints were taken: some did not improve readability, some even made the code noticeably _less_ readable.
|
@claude please review this PR. |
|
Claude finished @rdeago's task in 6m 16s —— View job Review of #340 — Review code style
Ric — I went through all 18 files. No correctness issues found: every change is behavior-preserving. Details on the three that needed a second look are at the bottom. What's left is one design point I'd push back on, two style-guide misses, and some subjective calls. CorrectnessClean. Three changes were non-obvious enough that I verified them rather than eyeballing:
The 1.
|
The token serves two contracts: it is the git push password, and it is the GitHub REST API credential. Folding the field into the PushPassword override made CreateGitHubClient source the API credential from a property whose contract is specifically "the password to use when pushing" — true by coincidence, not by contract, and a trap if push ever moves to a narrower credential. Restore the _token field and let both uses read from it. A suppression comment records why the ConvertToAutoProperty hint is declined here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The unparenthesized form is equivalent — `and` binds tighter than `or` — but it makes five lines that look like peer `or` operands depend on the reader knowing pattern-combinator precedence, and it is fragile under editing: inserting `or FormatException` after the ArgumentException line silently rebinds `and not ArgumentNullException` to it, with no compiler complaint. The parentheses also mirror the XML doc above. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The line was modified by this branch (`new StageOptions()` -> `new StageOptions`) and stayed at 161 characters; the line-length rule requires new and modified lines to comply. The other over-long lines in this file are untouched and fall under the mechanical-sweep carve-out. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The extension-block template mandates a summary comment. Wording matches the near-twin in Buildvana.Core.Process, also internal and also over StringBuilder. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ParseBool was duplicated, byte for byte, in ReleaseSettings and VersionAdvanceSettings. CliOptionReader already owns option-token semantics and already throws BuildFailedException for bad option usage, so the parsing belongs there rather than in a helper beside the two settings classes: the call sites stop naming each option twice. The diagnostic message is unchanged, since both call sites passed the long name as the option name. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both loop bodies were a single `if` with a two-statement body, already at one nesting level, so inverting to a `continue` guard turned four lines into seven and removed no nesting. Unlike the GitService rewrite, which collapsed three levels into one and stays. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Past the type guard, schema and root are the same object. Returning root spares the reader a moment's doubt about whether the Insert calls are reflected in what comes back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
TUnitAssertions0015 rejects IsEqualTo(true) / IsEqualTo(false). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Thanks — good review. Took six of the seven findings; the one I deviated on is #5, where I think there's a better home than the one proposed. All eight commits are pushed, and the sanity-check gate ( Addressed1. 2. 3. 4. 6. Both guard clauses reverted. Agreed — no de-nesting, three lines each. Both files are now byte-identical to Nit — Deviated5. CheckPublicApi = ParseBool(reader.ReadValue("--check-public-api"), "--check-public-api"),
One more commit
Not verifiedYou couldn't build; I could. The gate ran the full clean + restore + build + test + pack chain plus ReSharper, all green, so the compile-level claims in your review are now confirmed rather than read. @claude please re-review. |
|
Claude finished @rdeago's task in 3m 30s —— View job Re-review of #340 — Review code style
Ric — verified all eight commits against Verification of the addressed findings
Your correction on the line count stands. On #5 —
|
Promote to warnings, so the inspectcode gate enforces them instead of leaving them to be spotted by eye during a hint-chasing pass: ConvertToConstant.Local, CanReplaceCastWithLambdaReturnType, and RedundantLambdaSignatureParentheses. Suppress ArrangeObjectCreationWhenTypeNotEvident: target-typed `new()` is used freely here, and whatever is being assigned already names the type. Hint is ReSharper's lowest severity, so silencing one means `none`. Suppress UseRawString, UseVerbatimString and RawStringCanBeSimplified together. The three disagree with each other by design, because which literal form shows a string best is context-dependent: a rule an inspection cannot make. The judgment they were nagging about is now written down under "String literals" in the C# style guide instead. Promoting ConvertToConstant.Local immediately surfaced four locals in SelfVersionServiceTests that a manual pass had missed; they are now const, matching the pattern already used in that file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
One more commit since the re-review request, so it isn't pointed at a stale head: Promoted to warning — Suppressed — That group is the interesting one. Two notes on things I checked rather than assumed:
@claude please re-review — the diff has grown since the last request. |
|
Claude finished @rdeago's task in 6m 12s —— View job Re-review of #340 — Review code style
Ric — read the new commit against the previous head. No correctness issues; nothing in One finding on the verification gap you opened yourself, one pre-existing conflict the new approach makes relevant, and one internal contradiction in the new prose that the repo's own code already disagrees with. What I verified in
|
| Typo in… | Effect | At risk? |
|---|---|---|
| a suppression (4 keys) | inspection stays at Hint; gate runs at WARNING, so it never fails | no — self-limiting |
| a promotion (3 keys) | inspection stays at Hint; gate stays green forever | yes |
A misspelled suppression costs nothing. A misspelled promotion is invisible by construction: absence of diagnostics is exactly what compliance looks like. Concretely — someone writes .Select(path => (MetadataReference)MetadataReference.CreateFromFile(path)) again next month, the gate goes green, and the rule you thought you'd bought is not there. That's the failure mode you guarded the other two against; this key just missed the sweep because its site was already clean.
The probe you already ran works verbatim here: restore the cast at JetBrainsAnnotationsExporter.cs:69, run the gate, confirm it reports at warning rather than hint, revert. Fix this →
2. .editorconfig and Buildvana.slnx.DotSettings disagree on UnusedMember.Global
.editorconfig:543 — resharper_unused_member_global_highlighting = none
Buildvana.slnx.DotSettings:427 — InspectionSeverities/=UnusedMember_002EGlobal → WARNING
Pre-existing, not this PR's doing, and I'd have left it alone — except that this commit makes .editorconfig the declared source of truth for inspection severities, and it's the one inspection where a second mechanism says the opposite. Whichever layer ReSharper resolves in favour of, one of those two lines is dead, and a reader has no way to tell which without running the tool. The other five InspectionSeverities entries in the DotSettings (AnnotateCanBeNull*, AnnotateNotNull*, ConvertToPrimaryConstructor) have no .editorconfig counterpart, so this is the only collision.
Deleting one of the two lines is a one-line change, which puts it squarely in "FIX. IT. NOW." territory rather than an issue — but which line goes is your call, since it's a real behavioral question and not a formatting one. Fix this →
While you're in that file: three IssueTypesToHide … DoShow entries are now stale — ConvertToConstant.Local (:63), RedundantLambdaSignatureParentheses (:351), UseVerbatimString (:402). Those are UI-filter entries, not severities, so they're harmless; the last one is simply unreachable now that the inspection is none. Cosmetic, mention it only because you'd be editing the file anyway.
3. The new section's bullets 1 and 4 give opposite answers for the same string
.claude/rules/csharp-style-guide.md:218 and :221
- Raw (
"""...""") when the content itself contains quotes or backslashes.- Verbatim (
@"...") … content heavy in backslashes but free of quotes, such as Windows paths.
@"C:\hooks\test.cs" satisfies both. Read top-down, bullet 1 says raw; read to the end, bullet 4 says verbatim. This isn't hypothetical — seven literals in the repo are exactly that shape and all follow bullet 4, so the repo's own code contradicts bullet 1 as written:
tests/Buildvana.Tool.Tests/FileBasedAppHelperTests.cs:28—@"C:\hooks\test.cs"tests/Buildvana.Tool.Tests/GitHubRepositoryUrlsTests.cs:42,58—@"docs\ConstantsSyntax.md",@"..\outside.md"src/Buildvana.Core.Versioning/VersionSpecExtensions-private.cs:17and three regex literals in the settings tests
The discriminator that actually works is quotes, not backslashes: raw and verbatim handle \ identically, and raw's win is that " needs neither escaping nor doubling — which is precisely the [^""]+ → [^"]+ example bullet 1 gives. Striking "or backslashes" from bullet 1 makes the list total and non-overlapping, and leaves both bullets agreeing with the code.
This matters more than a normal doc nit because the section is now the only arbiter — the three inspections that used to nag about this are off, so a future sweep has nothing but these five bullets to go on. Fix this →
Clearly good
- The
.editorconfig→.claude/rules/cross-reference (:581). Someone editing severities who has never opened.claude/now gets pointed at the reasoning instead of re-deriving it, and the rules file explains the suppression instead of just asserting it. That closes the loop the group suppression would otherwise have opened. - The promote/suppress split is drawn on the right axis — mechanical-with-no-exception goes to the gate, judgment-call goes to prose.
ConvertToConstant.Localcatching four missed locals on its first run is the argument for the first half; the three literal-form inspections disagreeing by construction is the argument for the second. - "Hint is the lowest severity ReSharper offers, so silencing one means
none" is accurate and pre-empts the obvious "why not just lower it?" question. c0093c7in its own commit rather than an amend, per the sanity-check rule.
Note on this checkout
This runner's working tree has .claude/rules/csharp-style-guide.md modified — the String literals section is absent from the file on disk while present in HEAD. That's this checkout's state, not your branch's; 8cfa82d contains the section correctly. I read the committed version via git show throughout and left the working tree untouched.
Verification status
Unchanged from last round: I did not build. Restore still needs Buildvana.Sdk 2.1.70-preview from the private feed, and I have no network access from this runner — I tried to check the four inspection IDs against JetBrains' inspection reference and could not reach it. So finding 1 is specifically "this key was never exercised", not "this key is wrong"; I have no way to confirm the spelling either direction from here, which is the whole reason the probe is worth five minutes. Your green gate covers compilation and tests.
Nothing blocking. Finding 1 is the one I'd act on before merge; 2 and 3 are cheap and your call.
· branch code-style-review
The rest of the file's over-long lines, wrapped in one pass now that the branch has worked in it: two invocations one argument per line, a lambda ternary split, three doc-comment paragraphs rewrapped, an object initializer expanded, and the compound path check moved into a local, per the "no multi-line conditions" rule. The last one was a URL, which cannot be wrapped without breaking click-through. Its 40-character commit SHA is abbreviated to 10 instead: GitHub resolves abbreviated SHAs in blob URLs, so the permalink still works and still pins the same commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Nothing subtle in six of them: two invocations wrapped one argument per line, a lambda ternary split across three lines, three doc-comment paragraphs rewrapped, an object initializer expanded, and the compound path check in The seventh is worth calling out, since it is the one judgment call in the commit. It was a URL: 144 characters, and unwrappable — splitting a URL across lines breaks click-through, which is the entire value of citing it. Rather than leave it over the limit or damage it, I abbreviated the 40-character commit SHA to 10. GitHub resolves abbreviated SHAs in blob URLs and redirects to the full commit, so the link still works and still pins the same revision, at 114 characters. Ten hex digits is well clear of collision range for that repository. Easy to revert to the full SHA if you would rather have the limit broken than the SHA shortened — the line is the only thing that changes either way. @claude no new review needed for this one unless you want to look at it — it is mechanical wrapping on top of the diff you are already reviewing. |
|
Claude finished @rdeago's task in 3m 1s —— View job
|
The <returns> line came along verbatim from ReadValue, where "the last value supplied" means the raw token. Here the return type is bool?, so that wording reads as the string the user typed rather than its parsed form. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The "String literals" section contradicted itself: the raw-string bullet claimed quotes or backslashes, while the verbatim bullet reserved backslash-heavy content for verbatim. A Windows path like @"C:\hooks\x.cs" satisfied both, and the repo's seven verbatim literals all follow the verbatim bullet. Raw and verbatim both take a backslash literally, so a backslash is no reason to prefer one over the other; raw's win is quotes. Saying so makes the list total and non-overlapping, and leaves both bullets agreeing with the code they describe. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Buildvana.slnx.DotSettings can express inspection severities too, and it did: six entries, one of which (UnusedMember.Global at WARNING) directly contradicted .editorconfig's `none`. A setting in two places is a setting no reader can resolve without running the tool. .editorconfig wins that race — flipping its line to `warning` surfaces 38 UnusedMember.Global instances, while the committed `none` leaves the gate green — so the DotSettings entry was already dead. Rather than delete just that one, move the whole InspectionSeverities block: the four Annotate* promotions and ConvertToPrimaryConstructor keep their severity in .editorconfig, UnusedMember.Global is dropped as a duplicate, and the file's UI-filter rows are left alone. Verified that the migrated ConvertToPrimaryConstructor key takes effect: a misspelling would restore the inspection to its default severity, and it stays absent from a HINT-severity run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both reviews addressed; First, a correction to my own record. My Addressed
On which mechanism wins, since the finding left it openMeasured rather than reasoned: flipping The other five moved across keeping their severity: the four Same spelling risk applied to the migration, so it got the same treatment: a misspelled key would restore One thing I introduced and am leavingThe |
Checklist of related issues / discussions
Proposed changes
Fixed some ReSharper hints.
Not all hints were taken: some did not improve readability, some even made the code noticeably less readable.
No behavior change is expected.
Additional changes
ParseBoolwas duplicated, byte for byte, inReleaseSettingsandVersionAdvanceSettings. Both copies are gone, replaced byCliOptionReader.ReadBoolValue, which reads the option and parses it in one call. Same diagnostic message, so no behavior change. Covered by new tests inCliOptionReaderTests.Retuned seven ReSharper hint severities in
.editorconfig, so that this kind of review is enforced by the gate rather than repeated by eye:ConvertToConstant.Local,CanReplaceCastWithLambdaReturnType,RedundantLambdaSignatureParentheses;ArrangeObjectCreationWhenTypeNotEvident, plusUseRawString,UseVerbatimStringandRawStringCanBeSimplifiedas a group — those three disagree with each other by design, and the judgment they were nagging about is now written down as a new String literals section in.claude/rules/csharp-style-guide.md.Promoting
ConvertToConstant.Localimmediately caught four locals inSelfVersionServiceTeststhat the manual pass had missed; they are nowconst.Made
.editorconfigthe only place ReSharper inspection severities are set.Buildvana.slnx.DotSettingsheld six more, one of which (UnusedMember.GlobalatWARNING) contradicted.editorconfig'snoneoutright..editorconfigwins that race, so the entry was already dead; the wholeInspectionSeveritiesblock moved out rather than just that one line, and the file's UI-filter rows were left alone.Brought
GitService.csfully within the line-length limit. The branch had already reworked that file, and the style guide asks for the leftover wraps as their own commit once that is the case.Fixed
.claude/tools/inspect.csexiting zero on a failed build in its non-gate modes. Those modes deliberately do not fail for findings, but a failed build is not a finding: nothing was analyzed. Since the VS Code task's problem matcher requires a file position, a build failure whose diagnostics carry none left the Problems panel empty behind a successful-looking task. A failed build now exits 2, exactly as a failedinspectcoderun already did; a build that merely reported diagnostics still exits zero. The--gatemode was already correct and is unchanged.Types of changes
This pull request introduces the following types of changes:
docsdirectory) update.gitattributes,.gitignore)Breaking changes
This pull request introduces breaking changes:
Checklist
docsdirectory) only: