Skip to content

fix: build cycle exception paths lazily - #46

Merged
AGiorgetti merged 1 commit into
developfrom
fix/codex-issue-32-lazy-cycle-paths
Oct 9, 2026
Merged

AGiorgetti merged 1 commit into
developfrom
fix/codex-issue-32-lazy-cycle-paths

Conversation

@AGiorgetti

@AGiorgetti AGiorgetti commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Fixes #32.

  • Retain cycle diagnostic paths as a private readonly leaf value plus immutable ancestor links. Successful recursive descent no longer copies full prefixes; format the complete path only when throwing.
  • Keep first named edges allocation-free, preserve one tracker per recursive call, and leave active-reference Enter/finally/Exit semantics unchanged.
  • Preserve exact direct/indirect/collection paths, the initiating public method name, sibling reuse, concurrency, exception cleanup, and no tracker for nonrecursive mappings.
  • Add 13 generator cases and a shared normally compiled example used by Basic, clean-package, framework/language, normal, trimmed, and Native AOT consumers. Synchronize consumer guidance and measured performance notes.
  • No public API, specification semantics, reflection, or runtime dispatch change.

Test-first and allocation evidence

  • On unchanged develop 7b19def74753df90cb3770c7410ff5d7a3951244, the initial 13-case suite produced two failures and 11 passing controls, zero skips. The failures establish quadratic-prefix allocation and missing compact path storage; fixture inputs compile without unrelated errors.
  • At depths 16/32/64/128/256, total tracked allocations fell from 3,032/9,200/31,000/111,792/421,520 to 1,744/3,560/7,440/15,528/32,392 bytes per mapping. Three rounds of 100 mappings after 40 warmups give identical values.
  • None allocations remain 512/1,024/2,048/4,096/8,192 bytes. Depths 1/2 remain 232/264 bytes, and 256 shallow sibling depth-2 chains remain 18,656 bytes. Runtime manual controls reject new first-edge path allocations.
  • Environment: Debian 13 Linux x64, AMD EPYC 9V74 host, SDK 10.0.401, runtime 10.0.12, Roslyn 4.8.0, C# 9 Release, one logical processor exposed to .NET.
  • These are total managed allocations, including destination and HashSet/tracker costs. Source construction/reporting are outside measurement. No latency, throughput, peak-memory, release acceptance, or general stack-safety claim; depth is capped at 256.

Local validation

  • Final Release solution build: zero warnings/errors.
  • Full generator: 917 passed; runtime: 5 passed; integration: 1 passed. Zero failures/skips. All 13 new focused tests and all three source samples pass.
  • Same-tracker private-harness tests prove active references unwind after converter and cycle failures; this is stronger than retrying a public method with a new tracker.
  • Actual clean-package netstandard2.0/C#9 generated source was inspected and retains compact paths and full exception metadata.
  • Independent read-only review found no scoped blocker. Consumer-skill validation and CRLF-aware diff checks pass.
  • Available packaging retry: 224 passed, two infrastructure failures, zero skips. All 12 framework/language combinations, normal/clean-package consumers, usage validation, package/API checks, and benchmark smoke pass. The shared cycle example executes in each framework/language consumer, including genuine netstandard2.0 references; actual netstandard2.0/C#9 generated source was inspected. Trimming and Native AOT fail before publish behavior is established at ILLink ComputeManagedAssemblies task-host creation (MSB4216 / Unix-domain SocketException 13). No local trimming/AOT success is claimed. The first local packaging attempt was interrupted by automatic approval-review cancellation and produced no final TRX; only the completed retry is counted.

Local environment limits

PowerShell and clang are absent; 49 PowerShell-dependent cases are unavailable locally. The established ILLink task-host socket restriction affects local trimming/Native AOT validation. No warning, assertion, dependency, prerequisite, credential, or security setting was weakened. The completed exact-head Windows/Linux and Roslyn CI below supplies the full-platform evidence.

Every uploaded blob and the remote tree matches the tested local source tree 4ff805481d91eb06d193eb1a890ea9ccd8213d2f.

CI and review

Exact-head CI run 37949984701 passed for c8585b2e700e0756168ebd6ed3e0931cf148d17e.

  • Windows and Linux each passed 1,198 tests: 917 generator, 275 packaging, five runtime, and one integration; zero failures/skips.
  • All six Roslyn 4.8.0/4.14.0/5.9.0 Windows/Linux jobs passed 917 tests each, zero failures/skips.
  • The full packaging suites include actual trimming/Native AOT execution and the PowerShell-dependent checks unavailable locally.
  • Release packaging, artifact verification, and NuGet publishing jobs were correctly skipped for this ordinary PR run.

This PR remains draft, mergeable, and stopped for human review. No merge, release, tag, NuGet publication, or workflow dispatch was performed. The previously documented nullable-intermediate enum defect is outside scope.

Prepared with OpenAI Codex.

Retain an inline first segment and immutable ancestor links instead of copying full path prefixes on successful recursion. Preserve exact exception metadata, active-path cleanup, shallow allocation behavior, and portable generated code. Add allocation, runtime, sample, and package-consumer coverage.

Fixes #32.

Co-authored-by: Codex <codex@openai.com>
@AGiorgetti
AGiorgetti marked this pull request as ready for review October 9, 2026 15:24
@AGiorgetti
AGiorgetti merged commit 9c48bfd into develop Oct 9, 2026
11 checks passed
@AGiorgetti
AGiorgetti deleted the fix/codex-issue-32-lazy-cycle-paths branch October 9, 2026 15:24
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.

[P3] Build cycle exception paths lazily to avoid quadratic deep-graph allocations

1 participant