Skip to content

Comments

Fix read_console crash on Unity 6.5 and batch-mode test stability (#761)#762

Merged
dsarno merged 3 commits intoCoplayDev:betafrom
dsarno:fix/read-console-instanceid-761
Feb 16, 2026
Merged

Fix read_console crash on Unity 6.5 and batch-mode test stability (#761)#762
dsarno merged 3 commits intoCoplayDev:betafrom
dsarno:fix/read-console-instanceid-761

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Feb 16, 2026

Summary

  • Remove unused LogEntry.instanceID reflection in ReadConsole.cs that fatally blocked initialization on Unity 6000.5.0a6 (fixes read_console fails on Unity 6000.5.0a6: UnityEditor.LogEntry.instanceID is missing #761)
  • Skip Collider.GeometryHolder in GameObjectSerializer to prevent native PhysX SEGV crash during batch-mode test runs (CI stability)
  • Fix CodexConfigHelperTests to work with both release and prerelease package versions (tests were hardcoded to prerelease arg ordering)
  • Add com.unity.test-framework as a package dependency -- the package has a hard compile dependency on it but did not declare it, causing CS0234/CS0246 errors on projects without Test Framework installed

Test plan

  • ReadConsole tests pass (2/2) on Unity 6000.3 batch mode
  • Full test suite passes (612/612, 44 intentionally skipped) on Unity 6000.3 batch mode -- no crash
  • Full test suite passes (612/612, 44 intentionally skipped) on Unity 2021.3 via MCP
  • read_console exercised live on 2021.3 -- filter, pagination, format, stacktrace modes all work
  • CodexConfigHelperTests now pass on both release and prerelease builds (previously 4 failures)
  • Verify on Unity 6000.5.0a6 (not available locally -- reporter can confirm)

Generated with Claude Code

Summary by Sourcery

Improve Unity integration stability by fixing console reflection issues, ensuring safe collider serialization, and supporting UnityEvent configuration via serialized properties and batch commands.

Bug Fixes:

  • Prevent ReadConsole initialization failures on newer Unity versions by removing reliance on the LogEntry.instanceID field.
  • Avoid native PhysX crashes during component serialization by skipping problematic Collider.GeometryHolder properties.
  • Ensure batch_execute preserves nested serialized property keys while still normalizing top-level parameter names.

Enhancements:

  • Route UnityEvent-based properties through Unity's SerializedProperty system to correctly persist persistent calls and serialized events.
  • Relax Codex configuration tests to validate uvx argument structure independent of prerelease-specific ordering.

Build:

  • Declare com.unity.test-framework as a package dependency to satisfy compile-time requirements on projects without the Test Framework installed.

Tests:

  • Add UnityEvent serialization tests for ComponentOps, including private serialized UnityEvents and end-to-end wiring via commands.
  • Add batch execution tests to verify key normalization behavior and regressions for existing batch commands.
  • Refactor CodexConfigHelper tests to share uvx argument validation logic across platform-specific cases.

Summary by CodeRabbit

  • Bug Fixes

    • Prevented native crashes when serializing Collider-derived components.
  • Tests

    • Improved test infrastructure with centralized validation and platform-specific mocking support.
  • Chores

    • Added Unity Test Framework dependency to enhance testing capabilities.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Feb 16, 2026

Reviewer's Guide

Implements robust UnityEvent setting via Unity SerializedProperty instead of reflection, ensures batch_execute only normalizes top-level parameter keys, removes fragile LogEntry.instanceID reflection, skips a crashy Collider.GeometryHolder property during serialization, relaxes CodexConfigHelper tests to handle both release and prerelease argument layouts, and adds com.unity.test-framework as an explicit package dependency.

Sequence diagram for UnityEvent setting via batch_execute and ComponentOps

sequenceDiagram
    actor Client
    participant BatchExecute
    participant ComponentOps
    participant SerializedObject
    participant SerializedProperty
    participant UnityEventTestComponent

    Client->>BatchExecute: ExecuteCommand(params JSON)
    Note over BatchExecute: NormalizeParameterKeys
    BatchExecute->>BatchExecute: ToCamelCase on top-level keys
    BatchExecute->>ComponentOps: SetProperty(component, propertyName, value, out error)

    activate ComponentOps
    ComponentOps->>ComponentOps: ResolveMemberType(componentType, propertyName, normalizedName)
    ComponentOps-->>ComponentOps: memberType
    alt memberType is UnityEventBase-derived
        ComponentOps->>ComponentOps: SetViaSerializedProperty(component, propertyName, normalizedName, value, out error)
        ComponentOps->>SerializedObject: new SerializedObject(component)
        SerializedObject-->>ComponentOps: serializedObject
        ComponentOps->>SerializedObject: FindProperty(propertyName)
        SerializedObject-->>ComponentOps: SerializedProperty
        alt SerializedProperty found
            loop Recursive set
                ComponentOps->>ComponentOps: SetSerializedPropertyRecursive(prop, token, error, depth)
                alt prop is array and token is JArray
                    ComponentOps->>SerializedProperty: set arraySize
                    ComponentOps->>SerializedProperty: GetArrayElementAtIndex(i)
                else prop is generic and token is JObject
                    ComponentOps->>ComponentOps: FindPropertyRelativeFuzzy(parent, key)
                else prop is ObjectReference
                    ComponentOps->>ComponentOps: SetObjectReference(prop, token, out error)
                else leaf type
                    ComponentOps->>ComponentOps: Coerce value via ParamCoercion
                end
            end
            ComponentOps->>SerializedObject: ApplyModifiedProperties
            SerializedObject-->>UnityEventTestComponent: updated UnityEvent backing data
        else SerializedProperty not found
            ComponentOps-->>BatchExecute: error
        end
        ComponentOps-->>BatchExecute: success
    else memberType is not UnityEvent
        ComponentOps->>ComponentOps: Reflective property/field set
        ComponentOps-->>BatchExecute: success
    end
    deactivate ComponentOps

    BatchExecute-->>Client: Command result
Loading

Updated class diagram for ComponentOps UnityEvent support and test component

classDiagram
    class ComponentOps {
        +bool SetProperty(Component component, string propertyName, JToken value, string error)
        -Type ResolveMemberType(Type componentType, string propertyName, string normalizedName)
        -bool SetViaSerializedProperty(Component component, string propertyName, string normalizedName, JToken value, string error)
        -bool SetSerializedPropertyRecursive(SerializedProperty prop, JToken value, string error, int depth)
        -SerializedProperty FindPropertyRelativeFuzzy(SerializedProperty parent, string key)
        -bool SetObjectReference(SerializedProperty prop, JToken value, string error)
        -bool SetEnum(SerializedProperty prop, JToken value, string error)
    }

    class UnityEventBase {
    }

    class UnityEventTestComponent {
        +UnityEvent onSimpleEvent
        +UnityEvent~float~ onFloatEvent
        -UnityEvent _onPrivateEvent
    }

    class SerializedObject {
        +SerializedObject(Object targetObject)
        +SerializedProperty FindProperty(string propertyPath)
        +void ApplyModifiedProperties()
        +void Update()
    }

    class SerializedProperty {
        +bool isArray
        +int arraySize
        +SerializedPropertyType propertyType
        +string propertyPath
        +string[] enumNames
        +int enumValueIndex
        +int depth
        +string name
        +SerializedObject serializedObject
        +SerializedProperty GetArrayElementAtIndex(int index)
        +SerializedProperty FindPropertyRelative(string relativePropertyPath)
        +bool Next(bool enterChildren)
        +SerializedProperty GetEndProperty()
        +static bool EqualContents(SerializedProperty x, SerializedProperty y)
        +int intValue
        +bool boolValue
        +float floatValue
        +string stringValue
        +Object objectReferenceValue
    }

    class Collider {
    }

    class GameObjectSerializer {
        +object GetComponentData(Component c, bool includeNonPublicSerialized, bool includeNonPublicNonSerialized)
    }

    ComponentOps ..> UnityEventBase : uses
    ComponentOps ..> SerializedObject : uses
    ComponentOps ..> SerializedProperty : uses
    ComponentOps ..> GameObjectSerializer : coordinates via Component operations
    UnityEventTestComponent --|> MonoBehaviour
    UnityEventTestComponent ..> UnityEventBase : UnityEvent fields derive from
    GameObjectSerializer ..> Collider : inspects type for GeometryHolder
    GameObjectSerializer ..> ComponentOps : uses SetProperty for component data
Loading

File-Level Changes

Change Details Files
Route UnityEvent property setting through Unity's SerializedProperty system and add support utilities/tests.
  • Detect UnityEventBase-derived members in SetProperty and delegate assignment to a SerializedProperty-based setter instead of reflection to preserve persistent calls.
  • Add helper methods to resolve member types, set SerializedProperty values recursively (including arrays, generics, enums, primitives, and object references), and perform fuzzy child property lookup to tolerate underscore-stripped keys.
  • Implement object reference resolution from instanceID, guid, or asset path and add enum-setting logic with validation.
  • Introduce UnityEventTestComponent and a suite of tests that verify UnityEvent persistent call wiring, private serialized UnityEvents, and that non-UnityEvent reflection-based SetProperty continues to work, including an end-to-end ManageComponents command path.
MCPForUnity/Editor/Helpers/ComponentOps.cs
TestProjects/UnityMCPTests/Assets/Scripts/TestAsmdef/UnityEventTestComponent.cs
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentOpsUnityEventTests.cs
Ensure batch_execute only normalizes top-level parameter keys and preserves nested JSON keys for serialized data, with regression coverage.
  • Change NormalizeParameterKeys to only camelCase the immediate properties and stop recursively normalizing nested objects/arrays, removing NormalizeArray/NormalizeToken helpers.
  • Add tests that validate nested keys with underscores (e.g., m_PersistentCalls) survive a batch_execute call and still drive UnityEvent wiring correctly.
  • Add tests that confirm snake_case top-level parameters are still normalized and that existing batch commands such as creating a GameObject continue to work.
MCPForUnity/Editor/Tools/BatchExecute.cs
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/BatchExecuteKeyPreservationTests.cs
Remove fragile reflection on LogEntry.instanceID from read_console to avoid crashes on newer Unity versions.
  • Stop reflecting the instanceID field from UnityEditor.LogEntry and drop it from the static initialization requirements.
  • Adjust initialization error checks and field reset logic to no longer depend on instanceID.
  • Remove the unused instanceID read from the log processing loop, leaving message/file/line handling intact.
MCPForUnity/Editor/Tools/ReadConsole.cs
Harden GameObjectSerializer against PhysX crashes by skipping problematic Collider properties.
  • Add a guard in GetComponentData to skip the GeometryHolder property for Collider-derived components, preventing native PhysX SEGVs during batch-mode runs.
MCPForUnity/Editor/Helpers/GameObjectSerializer.cs
Make CodexConfigHelper tests resilient to both release and prerelease uvx argument layouts.
  • Introduce a shared AssertValidUvxArgs helper that validates presence/ordering of --from, the mcpforunityserver PyPI reference, the mcp-for-unity package name, and optional --prerelease explicit flags.
  • Update CodexConfigHelper tests for Windows/non-Windows and build/upsert paths to use the shared helper instead of asserting a fixed positional prerelease layout.
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs
Declare com.unity.test-framework as an explicit package dependency to satisfy compile-time requirements.
  • Add com.unity.test-framework (1.1.31) to the package.json dependencies list so projects without the Test Framework installed no longer hit missing type/namespace compiler errors.
MCPForUnity/package.json

Assessment against linked issues

Issue Objective Addressed Explanation
#761 Update ReadConsole to avoid fatal reflection errors when UnityEditor.LogEntry.instanceID is missing in newer Unity versions (e.g., 6000.5.0a6), so that read_console initializes successfully and can return console entries.

Possibly linked issues

  • #: PR removes the fatal LogEntry.instanceID reflection, directly fixing read_console initialization failure on Unity 6000.5.0a6.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR fixes Unity 6.5 compatibility by removing deprecated instanceID reflection in ReadConsole, adds skip logic for Collider.GeometryHolder to prevent crashes, improves resource management in ComponentOps, adds test-framework dependency, and refactors console validation test helpers.

Changes

Cohort / File(s) Summary
Component Serialization & Type Handling
MCPForUnity/Editor/Helpers/ComponentOps.cs, MCPForUnity/Editor/Helpers/GameObjectSerializer.cs
ComponentOps now disposes SerializedObject within a using scope and handles null string values by setting empty strings. GameObjectSerializer adds skip condition for Collider.GeometryHolder property to prevent native crashes and updates GetComponentData signature.
Console Log Reading
MCPForUnity/Editor/Tools/ReadConsole.cs
Removes all instanceID reflection code and GetRemappedTypeForFiltering helper to fix Unity 6.5 compatibility where LogEntry.instanceID is missing. Simplifies initialization and log extraction logic.
Package Dependencies
MCPForUnity/package.json
Adds com.unity.test-framework 1.1.31 dependency.
Test Infrastructure
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs
Introduces centralized AssertValidUvxArgs helper and MockPlatformService class to reduce test boilerplate and improve validation consistency.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • #762: Directly overlaps with same editor helper files (ComponentOps, GameObjectSerializer, ReadConsole) and package dependency changes.
  • #652: Modifies CodexConfigHelperTests to update uvx command argument validation with new --prerelease handling.
  • #202: Modifies ReadConsole.cs log severity classification and filtering logic alongside the removal of GetRemappedTypeForFiltering.

Suggested labels

bug

Poem

🐰 Hops with glee across Unity's halls,
No more instanceID in those console calls!
Colliders skip their geometry neat,
Resources disposed—cleanup complete!
Six-point-five compat, now smooth as can be,
Tests all refactored, fresh as spring tea!

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (6 files):

⚔️ .github/workflows/claude-nl-suite.yml (content)
⚔️ MCPForUnity/Editor/Helpers/ComponentOps.cs (content)
⚔️ MCPForUnity/Editor/Helpers/GameObjectSerializer.cs (content)
⚔️ MCPForUnity/Editor/Tools/ReadConsole.cs (content)
⚔️ MCPForUnity/package.json (content)
⚔️ TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs (content)

These conflicts must be resolved before merging into beta.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main objectives: fixing read_console crash on Unity 6.5 and improving batch-mode test stability, both of which are central to this PR.
Description check ✅ Passed The PR description comprehensively covers all changes made, testing performed, and related issues, though it deviates from the provided template structure and format.
Linked Issues check ✅ Passed The PR successfully addresses issue #761 by removing the LogEntry.instanceID reflection that caused initialization failures on Unity 6.5, restoring read_console functionality as required.
Out of Scope Changes check ✅ Passed All changes are well-scoped to the stated objectives: ReadConsole.cs fixes address #761, GameObjectSerializer changes prevent crashes, test updates validate new/fixed functionality, and the package dependency is a necessary build fix.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@MCPForUnity/Editor/Helpers/ComponentOps.cs`:
- Around line 517-519: The branch handling SerializedPropertyType.String should
assign an empty string rather than null to prop.stringValue; change the fallback
from null to string.Empty (or "") when value is null or value.Type ==
JTokenType.Null so prop.stringValue = value == null || value.Type ==
JTokenType.Null ? string.Empty : value.ToString();—update the code in the case
for SerializedPropertyType.String that sets prop.stringValue.
- Around line 412-430: The SetViaSerializedProperty method creates a
SerializedObject (var so = new SerializedObject(component)) but never disposes
it; wrap the SerializedObject in a using block so it is always disposed even on
early returns, e.g. change the method to create the SerializedObject inside a
using (...) { ... } scope, keep the FindProperty/SetSerializedPropertyRecursive
calls and so.ApplyModifiedProperties() inside that scope, and ensure out error
returns still occur inside the using so disposal is guaranteed (referencing
SetViaSerializedProperty, the local variable so, and
SetSerializedPropertyRecursive).
- Around line 484-496: The integer coercion uses int.MinValue as a failure
sentinel which wrongly rejects legitimate int.MinValue assignments; update
ParamCoercion.CoerceInt to return a nullable int (int?) or a (bool success, int
value) tuple, then change the SerializedPropertyType.Integer branch in
ComponentOps (the switch handling the int case) to call the new API, check the
explicit success flag/null before running the existing JToken-type checks, and
only set prop.intValue when the coercion succeeded; preserve the existing error
string logic when coercion fails.
- Around line 606-623: The heuristic that treats any string containing '/' as an
asset path is too permissive; update the branch in the value.Type ==
JTokenType.String handling so it only treats a string as a path when it clearly
looks like one (e.g., strVal.StartsWith("Assets/",
StringComparison.OrdinalIgnoreCase) || strVal.StartsWith("Packages/",
StringComparison.OrdinalIgnoreCase)) instead of using strVal.Contains("/"); keep
using AssetPathUtility.SanitizeAssetPath and
AssetDatabase.LoadAssetAtPath<UnityEngine.Object> to resolve, set
prop.objectReferenceValue on success and return false with the same error
message on failure.
- Around line 629-659: Add a brief inline comment inside
FindPropertyRelativeFuzzy explaining that the underscore-insensitive matching
can produce false positives when two sibling properties differ only by
underscores (e.g., "m_Value" vs "mValue"), that this is an intentional pragmatic
fallback for transport-stripped underscores, and that the code assumes such
collisions are unlikely in Unity serialized data; reference the method name
FindPropertyRelativeFuzzy and the normalizedKey/normalizedName comparison to
indicate where the comment should be placed.

In `@MCPForUnity/Editor/Tools/ReadConsole.cs`:
- Around line 514-531: Remove the dead private static method
GetRemappedTypeForFiltering from the ReadConsole class: delete the entire method
definition (the switch block returning remapped LogType values) since it is
unused anywhere in the codebase; after removal, run a quick compile to ensure no
callers exist and remove any now-unused usings only if the compiler flags them.

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs`:
- Around line 20-38: In AssertValidUvxArgs, make the TomlString cast and
prerelease lookup defensive: when building argValues from args.Children, check
each child is a TomlString (use the result of the cast != null) and call
Assert.Fail with a clear message if a non-string node is encountered; likewise,
before checking argValues[prereleaseIndex + 1], ensure prereleaseIndex + 1 <
argValues.Count and Assert.Fail with a descriptive message if it isn’t,
otherwise perform the equality assertion. This keeps AssertValidUvxArgs robust
and yields clear diagnostics on failure.

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/BatchExecuteKeyPreservationTests.cs`:
- Line 15: Add the NUnit [TestFixture] attribute to the
BatchExecuteKeyPreservationTests class to make the test intent explicit; ensure
NUnit.Framework is imported (using NUnit.Framework) if not already, then
annotate the class declaration public class BatchExecuteKeyPreservationTests
with [TestFixture].

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentOpsUnityEventTests.cs`:
- Around line 35-50: Extract a small helper method (e.g.,
MakePersistentCallJson(int targetId, string methodName, bool boolArg, int mode =
6, int callState = 2)) that builds and returns the JObject/string for the
m_PersistentCalls -> m_Calls entry used in ComponentOpsUnityEventTests; replace
the repeated inline JSON blocks (the JObject.Parse(...) that contains
"m_PersistentCalls" and the inner "m_Calls" object) in the tests with calls to
this helper, and for tests that need multiple entries create a small wrapper
like MakePersistentCallsArray(...) or call the helper multiple times to assemble
the array, keeping parameter names targetId, methodName, and boolArg to match
existing usage.
🧹 Nitpick comments (7)
🤖 Fix all nitpicks with AI agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.

In `@MCPForUnity/Editor/Helpers/ComponentOps.cs`:
- Around line 484-496: The integer coercion uses int.MinValue as a failure
sentinel which wrongly rejects legitimate int.MinValue assignments; update
ParamCoercion.CoerceInt to return a nullable int (int?) or a (bool success, int
value) tuple, then change the SerializedPropertyType.Integer branch in
ComponentOps (the switch handling the int case) to call the new API, check the
explicit success flag/null before running the existing JToken-type checks, and
only set prop.intValue when the coercion succeeded; preserve the existing error
string logic when coercion fails.
- Around line 606-623: The heuristic that treats any string containing '/' as an
asset path is too permissive; update the branch in the value.Type ==
JTokenType.String handling so it only treats a string as a path when it clearly
looks like one (e.g., strVal.StartsWith("Assets/",
StringComparison.OrdinalIgnoreCase) || strVal.StartsWith("Packages/",
StringComparison.OrdinalIgnoreCase)) instead of using strVal.Contains("/"); keep
using AssetPathUtility.SanitizeAssetPath and
AssetDatabase.LoadAssetAtPath<UnityEngine.Object> to resolve, set
prop.objectReferenceValue on success and return false with the same error
message on failure.
- Around line 629-659: Add a brief inline comment inside
FindPropertyRelativeFuzzy explaining that the underscore-insensitive matching
can produce false positives when two sibling properties differ only by
underscores (e.g., "m_Value" vs "mValue"), that this is an intentional pragmatic
fallback for transport-stripped underscores, and that the code assumes such
collisions are unlikely in Unity serialized data; reference the method name
FindPropertyRelativeFuzzy and the normalizedKey/normalizedName comparison to
indicate where the comment should be placed.

In `@MCPForUnity/Editor/Tools/ReadConsole.cs`:
- Around line 514-531: Remove the dead private static method
GetRemappedTypeForFiltering from the ReadConsole class: delete the entire method
definition (the switch block returning remapped LogType values) since it is
unused anywhere in the codebase; after removal, run a quick compile to ensure no
callers exist and remove any now-unused usings only if the compiler flags them.

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs`:
- Around line 20-38: In AssertValidUvxArgs, make the TomlString cast and
prerelease lookup defensive: when building argValues from args.Children, check
each child is a TomlString (use the result of the cast != null) and call
Assert.Fail with a clear message if a non-string node is encountered; likewise,
before checking argValues[prereleaseIndex + 1], ensure prereleaseIndex + 1 <
argValues.Count and Assert.Fail with a descriptive message if it isn’t,
otherwise perform the equality assertion. This keeps AssertValidUvxArgs robust
and yields clear diagnostics on failure.

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/BatchExecuteKeyPreservationTests.cs`:
- Line 15: Add the NUnit [TestFixture] attribute to the
BatchExecuteKeyPreservationTests class to make the test intent explicit; ensure
NUnit.Framework is imported (using NUnit.Framework) if not already, then
annotate the class declaration public class BatchExecuteKeyPreservationTests
with [TestFixture].

In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentOpsUnityEventTests.cs`:
- Around line 35-50: Extract a small helper method (e.g.,
MakePersistentCallJson(int targetId, string methodName, bool boolArg, int mode =
6, int callState = 2)) that builds and returns the JObject/string for the
m_PersistentCalls -> m_Calls entry used in ComponentOpsUnityEventTests; replace
the repeated inline JSON blocks (the JObject.Parse(...) that contains
"m_PersistentCalls" and the inner "m_Calls" object) in the tests with calls to
this helper, and for tests that need multiple entries create a small wrapper
like MakePersistentCallsArray(...) or call the helper multiple times to assemble
the array, keeping parameter names targetId, methodName, and boolArg to match
existing usage.
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs (1)

20-38: Good extraction of shared validation logic.

The helper cleanly consolidates repeated assertions and correctly handles both release and prerelease arg orderings, matching the GetBetaServerFromArgsList contract in AssetPathUtility.cs.

Two minor robustness notes for test diagnostics:

  1. Line 24(child as TomlString).Value will throw NullReferenceException if any child isn't a TomlString, producing a confusing failure instead of a clear assertion message.
  2. Line 36argValues[prereleaseIndex + 1] has no bounds guard if --prerelease happens to be the last element.

Neither is likely to bite given the controlled inputs, but a small tweak would yield better diagnostics on failure:

💡 Optional: safer casting with a clearer failure message
             var argValues = new List<string>();
             foreach (TomlNode child in args.Children)
-                argValues.Add((child as TomlString).Value);
+            {
+                Assert.IsInstanceOf<TomlString>(child, $"Expected TomlString but got {child?.GetType().Name}");
+                argValues.Add(((TomlString)child).Value);
+            }
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Helpers/CodexConfigHelperTests.cs`
around lines 20 - 38, In AssertValidUvxArgs, make the TomlString cast and
prerelease lookup defensive: when building argValues from args.Children, check
each child is a TomlString (use the result of the cast != null) and call
Assert.Fail with a clear message if a non-string node is encountered; likewise,
before checking argValues[prereleaseIndex + 1], ensure prereleaseIndex + 1 <
argValues.Count and Assert.Fail with a descriptive message if it isn’t,
otherwise perform the equality assertion. This keeps AssertValidUvxArgs robust
and yields clear diagnostics on failure.
MCPForUnity/Editor/Helpers/ComponentOps.cs (3)

484-496: int.MinValue as a sentinel for coercion failure is fragile.

If a caller legitimately wants to set a serialized int property to int.MinValue, this logic would reject it. The NaN sentinel used for float (line 508) is better because NaN is inherently "not a valid number." Consider returning a success/failure tuple from ParamCoercion.CoerceInt or using a nullable return instead, though the risk here is very low in practice.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@MCPForUnity/Editor/Helpers/ComponentOps.cs` around lines 484 - 496, The
integer coercion uses int.MinValue as a failure sentinel which wrongly rejects
legitimate int.MinValue assignments; update ParamCoercion.CoerceInt to return a
nullable int (int?) or a (bool success, int value) tuple, then change the
SerializedPropertyType.Integer branch in ComponentOps (the switch handling the
int case) to call the new API, check the explicit success flag/null before
running the existing JToken-type checks, and only set prop.intValue when the
coercion succeeded; preserve the existing error string logic when coercion
fails.

606-623: Broad heuristic for path detection — any string containing / is treated as an asset path.

The check strVal.Contains("/") (line 609) is very permissive. Strings like "on/off", "true/false", or component type names with namespaces could inadvertently match. Consider tightening the check, e.g., also verifying the string doesn't start with common non-path patterns, or only accepting strings that start with "Assets/" or "Packages/".

♻️ Suggested tightening
-if (strVal.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) || strVal.Contains("/"))
+if (strVal.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) ||
+    strVal.StartsWith("Packages/", StringComparison.OrdinalIgnoreCase))
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@MCPForUnity/Editor/Helpers/ComponentOps.cs` around lines 606 - 623, The
heuristic that treats any string containing '/' as an asset path is too
permissive; update the branch in the value.Type == JTokenType.String handling so
it only treats a string as a path when it clearly looks like one (e.g.,
strVal.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) ||
strVal.StartsWith("Packages/", StringComparison.OrdinalIgnoreCase)) instead of
using strVal.Contains("/"); keep using AssetPathUtility.SanitizeAssetPath and
AssetDatabase.LoadAssetAtPath<UnityEngine.Object> to resolve, set
prop.objectReferenceValue on success and return false with the same error
message on failure.

629-659: FindPropertyRelativeFuzzy is a pragmatic workaround — document the risk of false matches.

The underscore-insensitive fuzzy matching could collide if two sibling properties differ only by underscores (e.g., m_Value vs mValue). This is unlikely in Unity's serialized data but worth a brief inline comment noting the assumption.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@MCPForUnity/Editor/Helpers/ComponentOps.cs` around lines 629 - 659, Add a
brief inline comment inside FindPropertyRelativeFuzzy explaining that the
underscore-insensitive matching can produce false positives when two sibling
properties differ only by underscores (e.g., "m_Value" vs "mValue"), that this
is an intentional pragmatic fallback for transport-stripped underscores, and
that the code assumes such collisions are unlikely in Unity serialized data;
reference the method name FindPropertyRelativeFuzzy and the
normalizedKey/normalizedName comparison to indicate where the comment should be
placed.
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/BatchExecuteKeyPreservationTests.cs (1)

15-15: Consider adding [TestFixture] attribute for convention.

While NUnit discovers test methods without it, adding [TestFixture] on the class is conventional and makes the intent explicit.

♻️ Suggested addition
+    [TestFixture]
     public class BatchExecuteKeyPreservationTests
🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/BatchExecuteKeyPreservationTests.cs`
at line 15, Add the NUnit [TestFixture] attribute to the
BatchExecuteKeyPreservationTests class to make the test intent explicit; ensure
NUnit.Framework is imported (using NUnit.Framework) if not already, then
annotate the class declaration public class BatchExecuteKeyPreservationTests
with [TestFixture].
MCPForUnity/Editor/Tools/ReadConsole.cs (1)

514-531: Remove unused GetRemappedTypeForFiltering method.

This private static method at lines 514–531 is never called anywhere in the codebase and can be safely removed to eliminate dead code.

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In `@MCPForUnity/Editor/Tools/ReadConsole.cs` around lines 514 - 531, Remove the
dead private static method GetRemappedTypeForFiltering from the ReadConsole
class: delete the entire method definition (the switch block returning remapped
LogType values) since it is unused anywhere in the codebase; after removal, run
a quick compile to ensure no callers exist and remove any now-unused usings only
if the compiler flags them.
TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentOpsUnityEventTests.cs (1)

35-50: Consider extracting a helper to build the UnityEvent JSON payload.

The same JSON structure for a persistent call (target, assembly type name, method name, mode, arguments, call state) is repeated across five tests with only minor variations (different m_BoolArgument values, different counts). A small helper like MakePersistentCallJson(int targetId, string method, bool boolArg) would reduce duplication and make the tests easier to maintain if Unity's serialization format ever changes.

Also applies to: 75-96, 117-130, 155-168, 204-217

🤖 Prompt for AI Agents
Before applying any fix, first verify the finding against the current code and
decide whether a code change is actually needed. If the finding is not valid or
no change is required, do not modify code for that item and briefly explain why
it was skipped.
In
`@TestProjects/UnityMCPTests/Assets/Tests/EditMode/Tools/ComponentOpsUnityEventTests.cs`
around lines 35 - 50, Extract a small helper method (e.g.,
MakePersistentCallJson(int targetId, string methodName, bool boolArg, int mode =
6, int callState = 2)) that builds and returns the JObject/string for the
m_PersistentCalls -> m_Calls entry used in ComponentOpsUnityEventTests; replace
the repeated inline JSON blocks (the JObject.Parse(...) that contains
"m_PersistentCalls" and the inner "m_Calls" object) in the tests with calls to
this helper, and for tests that need multiple entries create a small wrapper
like MakePersistentCallsArray(...) or call the helper multiple times to assemble
the array, keeping parameter names targetId, methodName, and boolArg to match
existing usage.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Fix all issues with AI agents
Verify each finding against the current code and only fix it if needed.


In `@MCPForUnity/Editor/Helpers/ComponentOps.cs`:
- Around line 484-496: The code treats int.MinValue as an error sentinel which
collides with a legitimate value; update the logic to use an explicit success
flag instead: change ParamCoercion.CoerceInt to a TryCoerceInt(out int result,
JToken value, int default) or add an out/bool overload and call that from the
SerializedPropertyType.Integer branch, rely on the returned bool to decide
success/failure (set error = "Expected integer value." and return false on
failure) and assign prop.intValue = result when true; alternatively, if you
prefer not to change ParamCoercion, first inspect value.Type
(JTokenType.Integer/String/Null) to decide failure vs. accepting int.MinValue,
but prefer the TryCoerceInt(out ...) approach for clarity.
- Around line 575-586: The GUID resolution code using guidToken,
AssetDatabase.GUIDToAssetPath and AssetDatabase.LoadAssetAtPath can silently
assign null to prop.objectReferenceValue if the path exists but the asset fails
to load; modify the logic in the GUID-handling block to check the result of
LoadAssetAtPath for null, and if null set error (including the GUID and resolved
path) and return false instead of assigning null to prop.objectReferenceValue;
keep the existing checks for empty path and only assign to
prop.objectReferenceValue after verifying the loaded asset is non-null.

Comment on lines 575 to 586
var guidToken = jObj["guid"];
if (guidToken != null)
{
string path = AssetDatabase.GUIDToAssetPath(guidToken.ToString());
if (string.IsNullOrEmpty(path))
{
error = $"No asset found for GUID '{guidToken}'.";
return false;
}
prop.objectReferenceValue = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
return true;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

GUID resolution may silently assign null if the asset exists in the database but fails to load.

GUIDToAssetPath can return a non-empty path for an asset that was deleted from disk but still tracked. LoadAssetAtPath would then return null, and prop.objectReferenceValue would be silently set to null without an error.

Suggested guard
                 string path = AssetDatabase.GUIDToAssetPath(guidToken.ToString());
                 if (string.IsNullOrEmpty(path))
                 {
                     error = $"No asset found for GUID '{guidToken}'.";
                     return false;
                 }
-                prop.objectReferenceValue = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
-                return true;
+                var loaded = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
+                if (loaded == null)
+                {
+                    error = $"Asset at path '{path}' (GUID '{guidToken}') could not be loaded.";
+                    return false;
+                }
+                prop.objectReferenceValue = loaded;
+                return true;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
var guidToken = jObj["guid"];
if (guidToken != null)
{
string path = AssetDatabase.GUIDToAssetPath(guidToken.ToString());
if (string.IsNullOrEmpty(path))
{
error = $"No asset found for GUID '{guidToken}'.";
return false;
}
prop.objectReferenceValue = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
return true;
}
var guidToken = jObj["guid"];
if (guidToken != null)
{
string path = AssetDatabase.GUIDToAssetPath(guidToken.ToString());
if (string.IsNullOrEmpty(path))
{
error = $"No asset found for GUID '{guidToken}'.";
return false;
}
var loaded = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path);
if (loaded == null)
{
error = $"Asset at path '{path}' (GUID '{guidToken}') could not be loaded.";
return false;
}
prop.objectReferenceValue = loaded;
return true;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@MCPForUnity/Editor/Helpers/ComponentOps.cs` around lines 575 - 586, The GUID
resolution code using guidToken, AssetDatabase.GUIDToAssetPath and
AssetDatabase.LoadAssetAtPath can silently assign null to
prop.objectReferenceValue if the path exists but the asset fails to load; modify
the logic in the GUID-handling block to check the result of LoadAssetAtPath for
null, and if null set error (including the GUID and resolved path) and return
false instead of assigning null to prop.objectReferenceValue; keep the existing
checks for empty path and only assign to prop.objectReferenceValue after
verifying the loaded asset is non-null.

dsarno and others added 3 commits February 16, 2026 13:16
…ash (CoplayDev#761)

- Remove unused LogEntry.instanceID reflection that fatally blocked
  read_console initialization on Unity 6000.5.0a6
- Skip Collider.GeometryHolder in GameObjectSerializer to prevent
  native PhysX SEGV in batch-mode test runs
- Fix CodexConfigHelperTests to work with both release and prerelease
  package versions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The package has a hard compile dependency on Test Framework
(RunTests, TestJobManager, TestRunnerService, etc.) but did not
declare it in package.json. Projects without Test Framework
installed would get CS0234/CS0246 errors on import.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e dead method

- Wrap SerializedObject in using block in SetViaSerializedProperty
- Use string.Empty instead of null for SerializedProperty.stringValue
- Remove unused GetRemappedTypeForFiltering from ReadConsole

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@dsarno dsarno force-pushed the fix/read-console-instanceid-761 branch from 93241f5 to 3f95d6c Compare February 16, 2026 21:17
@dsarno dsarno merged commit 783d63c into CoplayDev:beta Feb 16, 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.

read_console fails on Unity 6000.5.0a6: UnityEditor.LogEntry.instanceID is missing

1 participant