Skip to content

fix(LC0089): keep compilation-scoped settings out of analyzer instance fields - #501

Merged
Arthurvdv merged 2 commits into
mainfrom
fix/lc0089-stateless-compilation-start
Sep 1, 2026
Merged

fix(LC0089): keep compilation-scoped settings out of analyzer instance fields#501
Arthurvdv merged 2 commits into
mainfrom
fix/lc0089-stateless-compilation-start

Conversation

@Arthurvdv

Copy link
Copy Markdown
Member

Problem

Issue #254 audited the RegisterCodeBlockAction analyzers for incremental-compilation staleness. Verification against the decompiled NAV SDK source (18.0.x) refuted the audit's core premise — the declaration-cache skipping machinery is dead code (null AnalysisState on every shipping driver path; CompilationWithAnalyzers never instantiated), there is no SyntaxNodeAction-vs-CodeBlockAction asymmetry, and the "LC0059 settings staleness" recommendation is moot because ALCopsSettingsProvider never invalidates its cache anyway. Full analysis: issue comment.

The verification did surface one real defect: CognitiveComplexity (LC0089/LC0089i/LC0090) stores per-compilation state in mutable instance fields, written at CompilationStart. Analyzer instances are materialized once per project and shared across analysis passes, so an overlapping pass or sibling project with a different alcops.json / ruleset can overwrite complexityThreshold and the LC0089i enablement flag mid-analysis — the same bug class as the LC0054 fix, and a violation of the repo's stateless-analyzer rule.

Solution

  • Capture both values as locals in the CompilationStart closure (like the existing recursion graph service) and thread them as parameters; the affected methods became static. No functional change under single-pass analysis.
  • Rewrite the incremental-compilation section of .claude/rules/sdk-analyzer-infrastructure.md to the verified model: no per-declaration cache skipping exists; the real callback filters are the per-file AnalysisScope and the module-only partial pass, uniform across all action kinds — which is also the actual mechanism behind the [Bug]: AC0032 - false positive #243 AC0032 false positives (the accumulator was scope-starved, not cache-skipped; the fix(AC0032): rewrite to atomic per-object analysis with variable-map optimization #253 fix remains correct, with corrected rationale). The two-phase accumulator anti-pattern verdict stands.
  • New rule doc .claude/rules/diagnostics/lc0089-cognitive-complexity.md recording the design decisions.

Testing

  • No new fixture: the race requires overlapping compilation passes against different settings, which unit tests cannot reproduce; existing tests pin the functional behavior (14/14 CognitiveComplexity tests pass).
  • Full solution: 1,593 passed, 0 failed.
  • Three-TFM Release build of ALCops.LinterCop (ContinuousIntegrationBuild=true): clean.
  • dotnet format --verify-no-changes: no findings.

Closes #254

🤖 Generated with Claude Code

Arthurvdv and others added 2 commits September 1, 2026 14:12
…instance fields

CognitiveComplexity stored the complexity threshold and the LC0089i
enablement flag in mutable instance fields written at CompilationStart.
Analyzer instances are shared across analysis passes and projects, so an
overlapping pass with a different alcops.json or ruleset could overwrite
them mid-analysis, applying the wrong threshold or increment enablement.

Capture both as locals in the CompilationStart closure (like the existing
recursion graph service) and thread them as parameters. No functional
change under single-pass analysis; the race is not reproducible in unit
tests, so no new fixture. Found while verifying issue #254.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verification of issue #254 against the decompiled NAV SDK showed the
documented declaration-cache skipping (AnalysisState.declarationAnalysisDataMap)
is dead code: every shipping driver path passes a null AnalysisState, so no
per-declaration action is ever cache-skipped, and there is no
SyntaxNodeAction-vs-CodeBlockAction asymmetry. The real callback filters are
the per-file AnalysisScope and the module-only partial pass, both uniform
across action kinds - which is also the actual mechanism behind the #243
AC0032 false positives. The two-phase accumulator anti-pattern verdict
stands, re-justified.

Also records the CognitiveComplexity design decisions in a new rule doc.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Arthurvdv
Arthurvdv merged commit a25889e into main Sep 1, 2026
53 checks passed
@Arthurvdv
Arthurvdv deleted the fix/lc0089-stateless-compilation-start branch September 1, 2026 12:55
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.

Audit: Analyzers using RegisterCodeBlockAction (incremental compilation risk)

1 participant