Skip to content

chore: EntityId Migration + Finalized Test Migration#243

Open
Eli Pinkerton (wallstop) wants to merge 1 commit into
masterfrom
dev/wallstop/master-plan-11
Open

chore: EntityId Migration + Finalized Test Migration#243
Eli Pinkerton (wallstop) wants to merge 1 commit into
masterfrom
dev/wallstop/master-plan-11

Conversation

@wallstop

@wallstop Eli Pinkerton (wallstop) commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Description

This PR updates DxMessaging for Unity's EntityId migration and completes the no-yield PlayMode test migration.

What changed:

  • Switched Unity object identity reads to a single version-gated source, InstanceId.StableId, to keep compatibility with Unity 6.4+ deprecations and Unity 6.5+ compile behavior while preserving the same 32-bit dispatch key.
  • Updated runtime/editor call sites that previously read GetInstanceID() directly to use the shared stable-id source.
  • Added InstanceIdSourceTests to lock migration behavior and guard against new direct GetInstanceID() usage outside the gated source.
  • Converted remaining no-yield PlayMode [UnityTest] methods to plain [Test] and tightened the contract test so the migration allowlist is now empty.
  • Updated user docs (README, compatibility, comparisons, and test-performance runbook) and internal AI testing guidance to reflect the completed migration and current benchmark framing.

User-facing impact:

  • No public API changes.
  • Package remains compatible across supported Unity versions, including Unity 6.5+ where GetInstanceID() is removed.
  • PlayMode test maintenance and runtime test performance improve by removing unnecessary coroutine wrappers.

Related Issue

Fixes #208

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactor (code change that neither fixes a bug nor adds a feature)

Checklist

  • All tests pass locally
  • Code is properly formatted
  • I have added tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have updated the CHANGELOG
  • My changes do not introduce breaking changes, or breaking changes are documented

Note

Medium Risk
Changes how Unity object IDs are sourced for dispatch and editor tooling on the Unity 6 migration path; behavior is heavily tested and the 32-bit key is intended to be unchanged, but any mistake would affect targeting and equality.

Overview
Routes all Unity object identity reads for the dispatch key through a new version-gated InstanceId.StableId: Unity 6.4+ uses EntityId.ToULong(...) (low 32 bits), older editors keep GetInstanceID(), with no public API change and the same 32-bit key semantics. Runtime/editor call sites that called GetInstanceID() directly now use StableId, and InstanceIdSourceTests locks parity plus a source-scan drift guard so GetInstanceID() cannot reappear outside the gated helper.

Finishes the PlayMode test cleanup by converting the remaining synchronous [UnityTest] methods to [Test] and clearing the pendingMigration allowlist in TestAttributeContractTests, so the no-yield rule applies tree-wide.

Docs and changelog are updated for Unity 6.5+ compatibility (#208), completed fast-test migration guidance, and Standalone IL2CPP-focused benchmark framing (README/comparisons/runbooks).

Reviewed by Cursor Bugbot for commit c357c2b. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI review requested due to automatic review settings June 20, 2026 04:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates DxMessaging to remain compatible with Unity’s ongoing Unity 6 object-identity (EntityId) migration by routing dispatch-key identity through a single version-gated source (InstanceId.StableId), and finishes the PlayMode “no-yield [UnityTest]” migration by converting remaining synchronous coroutine-shaped tests to plain [Test]. It also updates documentation, changelog entries, and internal AI/testing guidance to reflect the completed migrations and current benchmarking framing.

Changes:

  • Introduces InstanceId.StableId(UnityEngine.Object) (Unity 6.4+ uses EntityId.ToULong(GetEntityId()) low 32 bits; older Unity uses GetInstanceID()), and updates runtime/editor call sites to use it.
  • Converts remaining synchronous PlayMode [UnityTest] IEnumerator ... yield break; tests to [Test] void ..., and makes the “pending migration” allowlist empty to enforce the rule repo-wide.
  • Adds InstanceIdSourceTests to lock parity with legacy IDs (where available) and to source-scan against direct GetInstanceID() usage outside the gated helper; updates docs/runbooks/changelog accordingly.

Reviewed changes

Copilot reviewed 22 out of 23 changed files in this pull request and generated no comments.

Show a summary per file
File Description
Tests/Runtime/Unity/MessagingComponentProviderIntegrationTests.cs Converts remaining no-yield [UnityTest] methods to [Test].
Tests/Runtime/Core/TestAttributeContractTests.cs Empties the pendingMigration allowlist and updates migration-complete commentary for the no-yield [UnityTest] guard.
Tests/Runtime/Core/OrderingAcrossEnableCyclesTests.cs Converts no-yield [UnityTest] methods to [Test].
Tests/Runtime/Core/NominalTests.cs Converts multiple no-yield [UnityTest] methods to [Test] and removes coroutine-only endings.
Tests/Runtime/Core/LifecycleEdgeCasesTests.cs Converts no-yield [UnityTest] methods to [Test] while preserving scenario parameterization.
Tests/Runtime/Core/EnablementTests.cs Converts a no-yield [UnityTest] method to [Test].
Tests/Runtime/Core/EdgeCaseTests.cs Converts multiple no-yield [UnityTest] methods to [Test].
Tests/Runtime/Core/DefaultBusFallbackTests.cs Converts remaining no-yield [UnityTest] methods to [Test].
Tests/Runtime/Core/BaseCallContractTests.cs Converts remaining no-yield [UnityTest] methods to [Test].
Tests/Runtime/Core/InstanceIdSourceTests.cs Adds tests validating StableId parity (where possible) and a drift-guard source scan to prevent reintroducing direct GetInstanceID() reads.
Tests/Runtime/Core/InstanceIdSourceTests.cs.meta Adds Unity meta for the new test script.
Runtime/Core/MessageBus/MessageRegistrationBuilder.cs Replaces direct GetInstanceID() usage with InstanceId.StableId(...) when resolving Unity owners.
Runtime/Core/InstanceId.cs Implements StableId(...) and routes Unity-object InstanceId construction through it.
Editor/Testing/MessagingComponentEditorHarness.cs Uses StableId for deterministic ordering of listener diagnostics views without calling GetInstanceID() directly.
Editor/CustomEditors/MessageAwareComponentInspectorOverlay.cs Uses StableId for repaint-latch identity on Unity 6 migration path.
README.md Updates performance badge text and benchmark framing/numbers to Standalone IL2CPP focus.
docs/runbooks/test-suite-performance.md Updates runbook to reflect completion of the no-yield test migration and empty allowlist.
docs/reference/compatibility.md Documents Unity 6 EntityId migration handling and Unity 6.5+ GetInstanceID() removal compatibility.
docs/architecture/comparisons.md Reframes comparisons around Standalone IL2CPP live tables and updates historical snapshot guidance/numbers.
CHANGELOG.md Adds changelog entry describing the EntityId/StableId migration and compatibility outcome for Unity 6.5+.
.llm/skills/testing/fast-unity-tests.md Updates internal testing skill doc to mark no-yield migration as complete.
.llm/skills/index.md Updates skill index metadata (line count).
.llm/context.md Updates AI agent guidance to reflect empty allowlist and completed migration status.
Files not reviewed (1)
  • Tests/Runtime/Core/InstanceIdSourceTests.cs.meta: Generated file

@wallstop Eli Pinkerton (wallstop) enabled auto-merge (squash) June 20, 2026 04:53
@github-actions

Copy link
Copy Markdown
Contributor

Dispatch throughput (Unity 6000.3.16f1)

Runner: 13th Gen Intel(R) Core(TM) i9-13900KF, 24C/32T @ 3000MHz; 64GB DDR5@4200; NVIDIA GeForce RTX 3060; Microsoft Windows 11 Pro N (10.0.26200)

Regenerated by CI from commit c357c2b (run logs). These numbers MOVED versus the committed doc; CI commits the refreshed doc directly to the default branch after this PR merges.

Latest CI benchmark run: Unity 6000.3.16f1, commit c357c2b7237b97f67c82f8a9465b7d96322a1c6e.

Runner: 13th Gen Intel(R) Core(TM) i9-13900KF, 24C/32T @ 3000MHz; 64GB DDR5@4200; NVIDIA GeForce RTX 3060; Microsoft Windows 11 Pro N (10.0.26200)

Dispatch throughput - Standalone (IL2CPP)

Platform: Standalone IL2CPP x64 Release (WindowsPlayer; Unity 6000.3.16f1).

Scenario Throughput / Wall clock Allocated bytes
Untargeted Flood (One Handler) 38.27 M emits/sec 0 B
Untargeted Flood (Four Handlers, One Priority) 24.29 M emits/sec 0 B
Untargeted Flood (Four Handlers, Four Priorities) 24.33 M emits/sec 0 B
Untargeted First Dispatch (Cold, Distinct Types) 0.203 ms 0 B
Targeted Flood (One Listener) 9.68 M emits/sec 0 B
Targeted Flood (Sixteen Listeners) 6.74 M emits/sec 0 B
Targeted First Dispatch (Cold, Distinct Types) 0.200 ms 0 B
Broadcast Flood (One Handler) 19.20 M emits/sec 0 B
Broadcast First Dispatch (Cold, Distinct Types) 0.207 ms 0 B
Interceptor Heavy (Four Interceptors) 3.07 M emits/sec 0 B
Post-Processing Heavy (Four Post-Processors) 11.78 M emits/sec 0 B
Registration Flood (1000 Types, Cold Bus) 529.570 ms 0 B
Registration Flood (1000 Types, Warm JIT) 15.807 ms 0 B
Deregistration Flood (1000 Types, Cold) 1.133 ms 0 B
Deregistration Flood (1000 Types, Warm JIT) 1.125 ms 0 B

Library comparison - throughput (Standalone (IL2CPP))

Technology Global -> 1 subscriber Global -> 16 subscribers Keyed/targeted -> 1 of many Priority-ordered dispatch Filtered/intercepted dispatch Post-processing dispatch Subscribe/unsubscribe churn Struct message (zero-copy)
DxMessaging 28.71 M emits/sec 9.93 M emits/sec 9.71 M emits/sec 21.24 M emits/sec 6.75 M emits/sec 12.53 M emits/sec 0.50 M emits/sec 27.76 M emits/sec
MessagePipe 84.99 M emits/sec 15.63 M emits/sec 9.86 M emits/sec N/A 60.24 M emits/sec N/A 2.06 M emits/sec 76.64 M emits/sec
UniRx MessageBroker 5.24 M emits/sec 2.73 M emits/sec N/A N/A N/A N/A 0.78 M emits/sec 4.35 M emits/sec
Zenject SignalBus 2.29 M emits/sec 1.15 M emits/sec N/A N/A N/A N/A 1.60 M emits/sec 2.08 M emits/sec
Unity Atoms 96.53 M emits/sec 33.70 M emits/sec 102.54 M emits/sec N/A N/A N/A 10.87 M emits/sec N/A
ScriptableObject channel 140.81 M emits/sec 21.39 M emits/sec 188.60 M emits/sec N/A N/A N/A 28.79 M emits/sec 145.36 M emits/sec
UnityEvent 78.69 M emits/sec 10.13 M emits/sec 76.82 M emits/sec N/A N/A N/A 3.46 M emits/sec 89.40 M emits/sec
C# event 375.45 M emits/sec 45.25 M emits/sec 68.99 M emits/sec N/A N/A N/A 10.73 M emits/sec 297.04 M emits/sec
Unity SendMessage 8.91 M emits/sec 0.94 M emits/sec 8.43 M emits/sec N/A N/A N/A N/A N/A

Library comparison - allocations, bytes per op (Standalone (IL2CPP))

Technology Global -> 1 subscriber Global -> 16 subscribers Keyed/targeted -> 1 of many Priority-ordered dispatch Filtered/intercepted dispatch Post-processing dispatch Subscribe/unsubscribe churn Struct message (zero-copy)
DxMessaging 0 0 0 0 0 0 0 0
MessagePipe 0 0 0 N/A 0 N/A 0 0
UniRx MessageBroker 0 0 N/A N/A N/A N/A 0 0
Zenject SignalBus 0 0 N/A N/A N/A N/A 0 0
Unity Atoms 0 0 0 N/A N/A N/A 0 N/A
ScriptableObject channel 0 0 0 N/A N/A N/A 0 0
UnityEvent 0 0 0 N/A N/A N/A 0 0
C# event 0 0 0 N/A N/A N/A 0 0
Unity SendMessage 0 0 0 N/A N/A N/A N/A N/A

@github-actions

Copy link
Copy Markdown
Contributor

DxMessaging perf deltas vs master baseline (Unity 6000.3.16f1, Standalone IL2CPP)

Regenerated by CI (run logs). Changed beyond tolerance: yes. Regression gate: passed.

Scenario Baseline Current Delta
Untargeted Flood (One Handler) 37.92 M emits/sec, 0 B 38.27 M emits/sec, 0 B +0.92%
Untargeted Flood (Four Handlers, One Priority) 23.43 M emits/sec, 0 B 24.29 M emits/sec, 0 B +3.68%
Untargeted Flood (Four Handlers, Four Priorities) 25.31 M emits/sec, 0 B 24.33 M emits/sec, 0 B -3.86%
Untargeted First Dispatch (Cold, Distinct Types) 0.195 ms, 0 B 0.203 ms, 0 B +4.10%
Targeted Flood (One Listener) 9.94 M emits/sec, 0 B 9.68 M emits/sec, 0 B -2.63%
Targeted Flood (Sixteen Listeners) 5.96 M emits/sec, 0 B 6.74 M emits/sec, 0 B +13.11%
Targeted First Dispatch (Cold, Distinct Types) 0.193 ms, 0 B 0.200 ms, 0 B +3.63%
Broadcast Flood (One Handler) 18.85 M emits/sec, 0 B 19.20 M emits/sec, 0 B +1.84%
Broadcast First Dispatch (Cold, Distinct Types) 0.206 ms, 0 B 0.207 ms, 0 B +0.49%
Interceptor Heavy (Four Interceptors) 3.04 M emits/sec, 0 B 3.07 M emits/sec, 0 B +0.79%
Post-Processing Heavy (Four Post-Processors) 11.08 M emits/sec, 0 B 11.78 M emits/sec, 0 B +6.38%
Registration Flood (1000 Types, Cold Bus) 594.028 ms, 0 B 529.570 ms, 0 B -10.85%
Registration Flood (1000 Types, Warm JIT) 10.841 ms, 0 B 15.807 ms, 0 B +45.81%
Deregistration Flood (1000 Types, Cold) 1.030 ms, 0 B 1.133 ms, 0 B +10.00%
Deregistration Flood (1000 Types, Warm JIT) 1.245 ms, 0 B 1.125 ms, 0 B -9.64%
Global -> 1 subscriber 27.84 M emits/sec, 0 B 28.71 M emits/sec, 0 B +3.10%
Global -> 16 subscribers 10.49 M emits/sec, 0 B 9.93 M emits/sec, 0 B -5.31%
Keyed/targeted -> 1 of many 10.63 M emits/sec, 0 B 9.71 M emits/sec, 0 B -8.64%
Priority-ordered dispatch 24.38 M emits/sec, 0 B 21.24 M emits/sec, 0 B -12.87%
Filtered/intercepted dispatch 7.54 M emits/sec, 0 B 6.75 M emits/sec, 0 B -10.44%
Post-processing dispatch 12.61 M emits/sec, 0 B 12.53 M emits/sec, 0 B -0.68%
Subscribe/unsubscribe churn 0.48 M emits/sec, 0 B 0.50 M emits/sec, 0 B +4.31%
Struct message (zero-copy) 28.55 M emits/sec, 0 B 27.76 M emits/sec, 0 B -2.75%

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.

[Feature]: Migrate to GetEntityId() for Untiy 6+

2 participants