Skip to content

fix: guard CFG002 constructor self-cycle hang and prep 0.7.22 release#107

Merged
georgepwall1991 merged 2 commits into
mainfrom
release/0.7.22
Jul 21, 2026
Merged

fix: guard CFG002 constructor self-cycle hang and prep 0.7.22 release#107
georgepwall1991 merged 2 commits into
mainfrom
release/0.7.22

Conversation

@georgepwall1991

@georgepwall1991 georgepwall1991 commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes an infinite-loop analyzer hang in the CFG002 constructor-overwrite proof and bundles the codex-verified hygiene/release-prep work for the 0.7.22 release.

The fix (headline)

OptionsTypeMetadata.TryResolveRuntimeConstructorEffect walked the runtime constructor chain in an unguarded while (true). A public parameterless constructor with a zero-argument : this() initializer — a CS0516 self-cycle, but well-formed broken-compilation input the analyzer must survive — re-selected the same parameterless constructor forever (the Arguments.Count > 0 guard skips zero arguments, an empty body classifies as a non-write, and the ThisConstructorInitializer branch looped with no visited set and no cancellation-token check). Because OptionsTypeMetadata.Create runs for every recognized OptionsBuilder<T> registration before any appsettings gating, the shape hung the analyzer.

The ThisConstructorInitializer branch now compares the resolved parameterless target against the current constructor (SymbolEqualityComparer.Default) and returns false (unprovable → conservative CFG002 report) instead of spinning. No hot-path allocation; the base-chain walk stays monotonic; no valid compiling program is affected because self-delegating constructors are illegal.

  • TDD: RED regression Cfg002_reports_required_with_satisfying_initializer_when_parameterless_constructor_chains_to_itself hung pre-fix (confirmed via a bounded 60s timeout) and passes in ~1s post-fix; plus a compiling parameterized-:this()-to-parameterless guard and a parameterized-:this()-with-no-parameterless-target regression covering the null-target fall-through. Added a CompilerDiagnostics.None verifier overload because the repros are CS0516/CS1729.

Hygiene (codex-verified)

  • CLAUDE.md: rule range corrected CFG001–CFG007CFG001–CFG009.
  • Untracked machine-specific files (.mcp.json, .grok/, obsolete .pi/analyzer-health/ snapshots) and ignored them plus .claude/settings.local.json, .superpowers/. Kept .plugin-config/ (portable) and .pi/extensions/ (project tooling) tracked.
  • Repaired the .pi analyzer-health extension: selectHighestPriorityWork returns undefined on an empty shortlist (no more fabricating the lowest-scored Health Baseline rule), the iterate handler stops with a monitor-only notice, and release tagging is now opt-in via --release. Fixed the matching analyzer-health.md line-38 automation contradiction.
  • Refreshed the analyzer-health.md evidence block (iteration-123 row, CFG002 Rule Notes, base commit advanced to 04fc74e).

Release prep

  • Version bump 0.7.210.7.22 across both .csproj (incl. PackageReleaseNotes), README install snippet, CHANGELOG, and the health-doc header.
  • AnalyzerReleases.Unshipped.md unchanged (no new diagnostic ID or severity).

Verification

  • Full suite: 933 passed (683 analyzer + 250 core; +3 new).
  • CI-mode build (ContinuousIntegrationBuild=true): 0 warnings / 0 errors.
  • dotnet format --verify-no-changes: clean · git diff --check: clean.
  • Independent codex review --uncommitted: no actionable defects.

Fix an infinite-loop analyzer hang in the CFG002 constructor-overwrite
proof. A public parameterless constructor with a zero-argument `: this()`
initializer (a CS0516 self-cycle, but well-formed broken-compilation input)
made TryResolveRuntimeConstructorEffect re-select the same constructor
forever. The ThisConstructorInitializer branch now compares the resolved
parameterless target against the current constructor and returns false
(unprovable, so the satisfying default is conservatively rejected and the
missing required key reported) instead of spinning. No valid compiling
program is affected because self-delegating constructors are illegal.

- TDD: RED regression hung pre-fix (confirmed via bounded timeout), passes
  post-fix; added a compiling parameterized-`:this()` guard and a
  CompilerDiagnostics.None verifier overload for the CS0516 repro.
- CLAUDE.md: rule range corrected to CFG001-CFG009.
- Untracked machine-specific tool artifacts (.mcp.json, .grok/, obsolete
  .pi/analyzer-health snapshots) and completed .gitignore; kept .plugin-config
  and .pi/extensions tracked.
- Repaired the .pi analyzer-health extension: monitor-only on an empty
  shortlist (no fabricated lowest-score target), release tagging opt-in via
  --release; fixed the matching analyzer-health.md automation note.
- Refreshed analyzer-health.md evidence (iteration 123, base commit 04fc74e).
- Version bump 0.7.21 -> 0.7.22 (both csproj, PackageReleaseNotes, README,
  CHANGELOG, health-doc header). No new diagnostic ID or severity.

Verification: 932 tests passed (682 analyzer + 250 core), CI-mode build
0 warnings/0 errors, format + git diff --check clean, codex review found no
actionable defects.
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

…erage

Add a parameterized-`: this()`-with-no-parameterless-target regression
(CS1729 broken code) that exercises the null-target fall-through in the
ThisConstructorInitializer branch, completing coverage of the iteration-123
fix. Update analyzer-health.md test counts (683 analyzer + 250 core = 933)
and regression-test lists to match.
@georgepwall1991
georgepwall1991 merged commit 2db53b9 into main Jul 21, 2026
4 checks passed
@georgepwall1991
georgepwall1991 deleted the release/0.7.22 branch July 21, 2026 20:13
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.

1 participant