Skip to content

Conversation

@dsarno
Copy link
Collaborator

@dsarno dsarno commented Jan 15, 2026

Cleans up obsolete GitHub workflows, makes unity-tests runnable on forks when valid Unity secrets are present, and tightens Claude NL suite licensing to avoid upstream entitlement failures.

Summary by Sourcery

Improve console tool robustness and simplify Unity-related CI workflows while tightening licensing requirements.

Bug Fixes:

Enhancements:

  • Normalize and validate read_console message type values, returning clear errors for invalid or non-string entries.
  • Allow the main Unity test workflow to run on forks when valid Unity license secrets are configured.
  • Tighten Unity licensing detection in the Claude NL suite workflow by requiring UNITY_SERIAL when using email/password-based activation.
  • Remove obsolete GitHub workflows that are superseded by the main Unity and Claude workflows.

CI:

  • Adjust Unity test and Claude NL suite workflows to conditionally run based on detected Unity license configuration and to skip tests cleanly when licensing is unavailable.

Tests:

  • Add integration tests covering JSON-string and list handling, normalization, and validation of the read_console types parameter.

Summary by CodeRabbit

  • New Features

    • Console reading now supports pagination with cursor-based navigation, timestamp filtering, output format selection (plain/detailed/json), and stacktrace control.
    • Enhanced types filtering with JSON string input support and validation.
  • Chores

    • Removed unused CI/CD workflows and updated Unity licensing requirements.
  • Tests

    • Added integration tests for console types parameter validation and JSON parsing.

✏️ Tip: You can customize this high-level summary in your review settings.

@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jan 15, 2026

Reviewer's Guide

Updates the read_console tool to accept and validate the console types parameter from both JSON strings and lists, expands integration test coverage for this behavior, and adjusts GitHub workflows to better handle Unity licensing (including forks) while removing obsolete workflows.

Sequence diagram for claude-nl-suite Unity licensing checks

sequenceDiagram
  participant GitHub
  participant Workflow as claude_nl_suite_workflow
  participant JobCheck as job_check_secrets
  participant JobRun as job_run_suite
  participant SecretsStore as GitHub_Secrets
  participant Unity as Unity_licensing_service

  GitHub->>Workflow: Trigger workflow dispatch
  Workflow->>JobCheck: Start check_secrets
  JobCheck->>SecretsStore: Read ANTHROPIC_API_KEY
  SecretsStore-->>JobCheck: Value or empty
  JobCheck->>JobCheck: Set anthropic_ok flag

  JobCheck->>SecretsStore: Read UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD, UNITY_SERIAL
  SecretsStore-->>JobCheck: Values or empty
  alt UNITY_LICENSE present OR (UNITY_EMAIL and UNITY_PASSWORD and UNITY_SERIAL present)
    JobCheck->>JobCheck: unity_ok = true
  else
    JobCheck->>JobCheck: unity_ok = false
  end
  JobCheck-->>Workflow: Output anthropic_ok, unity_ok

  Workflow->>JobRun: Start run_suite with outputs
  JobRun->>SecretsStore: Read UNITY_LICENSE, UNITY_EMAIL, UNITY_PASSWORD, UNITY_SERIAL
  SecretsStore-->>JobRun: Values or empty

  JobRun->>JobRun: use_ulf = UNITY_LICENSE present
  JobRun->>JobRun: use_ebl = UNITY_EMAIL and UNITY_PASSWORD and UNITY_SERIAL present
  JobRun->>JobRun: has_serial = UNITY_SERIAL present

  alt use_ulf is true
    JobRun->>Unity: Activate with ULF license
  else use_ebl is true
    JobRun->>Unity: Activate with email/password/serial
  else
    JobRun->>JobRun: Skip Unity-dependent tests
  end
Loading

Flow diagram for read_console types parsing and validation

flowchart TD
  A_start["read_console called"] --> B_check_types_nil{"types is None?"}
  B_check_types_nil -- "Yes" --> B1_set_default["Set types = ['error','warning','log']"]
  B1_set_default --> C_set_format_default["Set format default if needed"]
  B_check_types_nil -- "No" --> D_is_str{"types is string?"}
  D_is_str -- "Yes" --> D1_parse_json["types = parse_json_payload(types)"]
  D1_parse_json --> E_validate_list
  D_is_str -- "No" --> E_validate_list{"types is list?"}
  E_validate_list -- "No" --> E1_error_not_list["Return error: types must be a list"]
  E_validate_list -- "Yes" --> F_iterate["For each entry in types"]
  F_iterate --> F1_check_str{"entry is string?"}
  F1_check_str -- "No" --> F1_error_not_str["Return error: types entries must be strings"]
  F1_check_str -- "Yes" --> F2_normalize["normalized = entry.strip().lower()"]
  F2_normalize --> F3_allowed{"normalized in {error, warning, log, all}?"}
  F3_allowed -- "No" --> F3_error_invalid["Return error: invalid types entry"]
  F3_allowed -- "Yes" --> F4_append["Append normalized to normalized_types"]
  F4_append --> F5_more{"More entries?"}
  F5_more -- "Yes" --> F_iterate
  F5_more -- "No" --> G_set_normalized["types = normalized_types"]
  G_set_normalized --> C_set_format_default
  C_set_format_default --> H_continue["Continue console read/clear logic"]
Loading

File-Level Changes

Change Details Files
Enhance read_console to robustly handle and validate the types parameter (including JSON string input) and normalize values.
  • Change the types parameter type annotation to accept either a list of allowed literals or a string, documenting that JSON strings are accepted.
  • Parse types when provided as a JSON string using parse_json_payload, returning a structured error if the result is not a list.
  • Validate that all types entries are strings, normalize them to lowercase, ensure they are in the allowed set, and return informative error messages for invalid entries.
  • Maintain a sensible default of ['error', 'warning', 'log'] when types is omitted.
Server/src/services/tools/read_console.py
Add integration tests covering JSON-string handling, normalization, and validation for the read_console types parameter.
  • Introduce an async test that verifies JSON-string types are parsed into a list, lowercased, and still work when passed as a list.
  • Introduce an async test that verifies invalid types entries (unknown values and non-strings) cause clear error responses and prevent calls to Unity.
  • Use monkeypatching of send_with_unity_instance to capture and assert on the parameters sent to the Unity integration.
Server/tests/integration/test_read_console_truncate.py
Update Unity-related GitHub workflows to better gate on license/secrets presence, support forks safely, and tighten licensing checks, while removing obsolete workflows.
  • Remove the repository-owner guard from the unity-tests workflow and instead add a step that detects presence of Unity license credentials, conditionally skipping tests and their artifacts when secrets are missing.
  • Ensure Unity test steps export UNITY_SERIAL in addition to existing Unity credentials and gate their execution on the detected license status.
  • Tighten the Claude NL suite workflow license detection and entitlement checks to require UNITY_SERIAL when using the email/password path.
  • Delete obsolete workflows for claude-gameobject-suite, claude-mcp-preflight, and unity-tests-fork.
.github/workflows/unity-tests.yml
.github/workflows/claude-nl-suite.yml
.github/workflows/claude-gameobject-suite.yml
.github/workflows/claude-mcp-preflight.yml
.github/workflows/unity-tests-fork.yml

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 Jan 15, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

This PR removes three GitHub Actions workflows, modifies license detection logic in two workflows requiring UNITY_SERIAL presence, and enhances the read_console service function with JSON string parsing, parameter validation, new paging/output parameters, and corresponding integration tests.

Changes

Cohort / File(s) Summary
Workflow Removals
.github/workflows/claude-gameobject-suite.yml, .github/workflows/claude-mcp-preflight.yml, .github/workflows/unity-tests-fork.yml
Deleted entire CI workflows: GameObject API test pipeline (637 lines), MCP preflight pipeline (55 lines), and fork-specific Unity test pipeline (199 lines)
License Detection Changes
.github/workflows/claude-nl-suite.yml
Tightened Unity license availability conditions to require UNITY_SERIAL presence alongside UNITY_EMAIL and UNITY_PASSWORD for both email+password and EBL licensing paths
Unity Test License Gating
.github/workflows/unity-tests.yml
Added new license detection step reading UNITY_LICENSE and credential secrets; introduced unity_ok gate to skip domain tests, standard tests, and artifact uploads when secrets are missing
Console Read Enhancement
Server/src/services/tools/read_console.py
Expanded function signature with new parameters (since_timestamp, page_size, cursor, format, include_stacktrace); added JSON string parsing for types parameter; implemented validation against allowed values {error, warning, log, all} with normalized lowercase handling and error reporting; added post-response stacktrace stripping logic
Console Read Tests
Server/tests/integration/test_read_console_truncate.py
Added integration tests for types parameter JSON string parsing and validation, verifying proper conversion, normalization, error handling, and no-send behavior on invalid input

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested labels

codex

Poem

🐰 The console speaks in measured tones,
Types parsed from JSON strings and stones,
Licenses checked with SERIAL grace,
Old workflows fade without a trace!

✨ Finishing touches
  • 📝 Generate docstrings


📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10e93b8 and dcfb995.

📒 Files selected for processing (7)
  • .github/workflows/claude-gameobject-suite.yml
  • .github/workflows/claude-mcp-preflight.yml
  • .github/workflows/claude-nl-suite.yml
  • .github/workflows/unity-tests-fork.yml
  • .github/workflows/unity-tests.yml
  • Server/src/services/tools/read_console.py
  • Server/tests/integration/test_read_console_truncate.py

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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.

@dsarno dsarno merged commit a4f74da into CoplayDev:main Jan 15, 2026
0 of 2 checks passed
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 found 2 issues

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location> `Server/tests/integration/test_read_console_truncate.py:210-219` </location>
<code_context>
+    # Test with types as JSON string (the problematic case from issue #561)
</code_context>

<issue_to_address>
**suggestion (testing):** Add tests for JSON `types` strings that do not parse to a list to cover the new validation branch.

Right now we only test valid JSON list strings. Please also add tests where `types` is a JSON string that parses to a non-list value, for example:
- `types='"error"'` → expect `success is False`, the "types must be a list" message, and that `send_with_unity_instance` is not called.
- `types='{"type": "error"}'` → same expectations.
These will exercise the new error-handling branch in `read_console`.
</issue_to_address>

### Comment 2
<location> `Server/tests/integration/test_read_console_truncate.py:188-197` </location>
<code_context>
+    assert captured["params"]["types"] == ["error", "warning"]
+
+
[email protected]
+async def test_read_console_types_validation(monkeypatch):
+    """Test that read_console validates types entries and rejects invalid values."""
+    tools = setup_tools()
</code_context>

<issue_to_address>
**suggestion (testing):** Add a test for the new "types must be a list" validation when a non-list, non-string is passed.

This new validation branch (when `types` is neither `None`, a list, nor a JSON string, e.g. `types=123` or `types=True`) isn’t covered yet. Please add a test that calls `read_console` with an invalid non-list value (like `types=123`) and asserts:
- `resp["success"] is False`
- the error message mentions that `types` must be a list / wrong type
- `send_with_unity_instance` is not called, consistent with the other negative tests.

Suggested implementation:

```python
@pytest.mark.asyncio
async def test_read_console_types_json_string(monkeypatch):
    """Test that read_console handles types parameter as JSON string (fixes issue #561)."""
    tools = setup_tools()
    read_console = tools["read_console"]

    captured = {}

    async def fake_send_with_unity_instance(_send_fn, _unity_instance, _command_type, params, **_kwargs):
        captured["params"] = params
        return {
            "success": True,
            "data": {"lines": [{"level": "error", "message": "test error"}]},
        }

    # Monkeypatch the function used by read_console to send the command to Unity.
    # NOTE: adjust the target path here to match where send_with_unity_instance is imported/used.
    monkeypatch.setattr(
        "Server.tools.console_tools.send_with_unity_instance",
        fake_send_with_unity_instance,
        raising=True,
    )

    # Pass types as a JSON string and ensure it is parsed to a list internally.
    resp = await read_console(types='["error", "warning"]')

    assert resp["success"] is True
    assert "data" in resp
    assert captured["params"]["types"] == ["error", "warning"]


@pytest.mark.asyncio
async def test_read_console_types_validation_non_list(monkeypatch):
    """Test that read_console rejects invalid non-list, non-string types values."""
    tools = setup_tools()
    read_console = tools["read_console"]

    calls = {"called": False}

    async def fake_send_with_unity_instance(*_args, **_kwargs):
        calls["called"] = True
        return {
            "success": True,
            "data": {"lines": []},
        }

    # Monkeypatch the function used by read_console to ensure it is NOT called for invalid input.
    # NOTE: adjust the target path here to match where send_with_unity_instance is imported/used.
    monkeypatch.setattr(
        "Server.tools.console_tools.send_with_unity_instance",
        fake_send_with_unity_instance,
        raising=True,
    )

    # Use an invalid non-list, non-string value for types (e.g. int) to trigger validation error.
    resp = await read_console(types=123)

    assert resp["success"] is False

    # Error message should mention that `types` must be a list / has wrong type.
    error_text = str(resp.get("error") or resp.get("message") or "")
    assert "type" in error_text.lower() or "list" in error_text.lower()
    assert "types" in error_text

    # When validation fails, send_with_unity_instance must not be called.
    assert calls["called"] is False

```

1. Replace `"Server.tools.console_tools.send_with_unity_instance"` in both `monkeypatch.setattr` calls with the actual import path used in `read_console` (e.g., if `read_console` does `from Server.tools.console_tools import send_with_unity_instance`, you should patch `"Server.tools.console_tools.send_with_unity_instance"`; if it re-exports it on a different object, patch that instead).
2. Ensure the way `read_console` is called (`await read_console(types=...)`) matches its real signature; if it expects a `params` dict or other arguments, adapt the calls accordingly while keeping the core idea: one call with a JSON string for the “happy path” test and one call with an invalid non-list value (e.g. `123`) for the new validation test.
3. If the error structure is different (for example, `resp` might be `{"success": False, "error": {"message": "..."}}`), update the `error_text` extraction logic so the assertions still check that the message mentions `types` and the requirement that it be a list / wrong type.
</issue_to_address>

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.

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