Skip to content

Stabilize codegen ordering for byte-identical output across runs#196

Merged
jeremydmiller merged 1 commit into
mainfrom
claude/sweet-vaughan-2f7cf6
Apr 28, 2026
Merged

Stabilize codegen ordering for byte-identical output across runs#196
jeremydmiller merged 1 commit into
mainfrom
claude/sweet-vaughan-2f7cf6

Conversation

@jeremydmiller
Copy link
Copy Markdown
Member

Summary

  • MethodFrameArranger.findInjectedFields and findSetters populated AllInjectedFields / Setters by iterating DependencyGatherer.Variables.Keys(), which is backed by an ImHashMap. ImHashMap iterates in hash-code order, and string/Type hash codes are randomized per process — so the same logical generated type produced constructor parameters and field declarations in different orders across runs, breaking byte-level file comparisons.
  • Sort the iteration by (VariableType.FullName, Usage/PropName) (ordinal) before filling, giving a stable, process-independent order. Base constructor arguments are unaffected (they are populated in InheritsFrom via GetParameters() declaration order, then deduped via Fill).
  • Added CodegenTests/CodeGeneration_ordering_determinism.cs with four tests:
    • asserts AllInjectedFields are sorted alphabetically,
    • asserts the generated constructor places parameters in alphabetical order,
    • asserts byte-identical output regardless of frame insertion order,
    • asserts byte-stability across repeated invocations.
      The first two failed on main (constructor was emitted as bravo, alpha, zebra, delta, charlie, mango) and pass with this change.

Test plan

  • dotnet test src/CodegenTests/CodegenTests.csproj — 309 passed
  • dotnet test src/CoreTests/CoreTests.csproj — 389 passed (×3 TFMs)
  • dotnet test src/CommandLineTests/CommandLineTests.csproj — 280 passed (×3 TFMs)
  • dotnet test src/EventTests/EventTests.csproj — 222 passed (×3 TFMs)
  • New CodeGeneration_ordering_determinism tests fail on main and pass with this change

🤖 Generated with Claude Code

The MethodFrameArranger gathered InjectedFields and Setters by iterating
DependencyGatherer.Variables.Keys(), which is backed by an ImHashMap.
ImHashMap iterates in hash-code order, and string/Type hash codes are
randomized per process - so the same logical generated type produced
constructor parameters and field declarations in different orders across
runs, breaking byte-level file comparisons.

Sort the iterations by (VariableType.FullName, Usage/PropName) before
filling AllInjectedFields and Setters so the generated source is stable.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@jeremydmiller jeremydmiller merged commit e8f882e into main Apr 28, 2026
1 check passed
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