Skip to content

fix(inspector,ci): stage-extraction exec-scoping crash + CI test deps#5

Merged
JosephOIbrahim merged 7 commits into
masterfrom
fix/inspector-scoping-and-ci-deps
May 29, 2026
Merged

fix(inspector,ci): stage-extraction exec-scoping crash + CI test deps#5
JosephOIbrahim merged 7 commits into
masterfrom
fix/inspector-scoping-and-ci-deps

Conversation

@JosephOIbrahim
Copy link
Copy Markdown
Owner

@JosephOIbrahim JosephOIbrahim commented May 29, 2026

Summary

Two open fixes from the SCOUT→FORGE session, both root-caused live on 21.0.671.

1. Inspector extraction_script_crash (real bug)

synapse_inspect_stage crashed with the generic HoudiniExtractionError: Extraction script crashed. Root cause: the bridge's execute_python runs the extraction script with split globals/locals, so the script's module-level import hou / import json are invisible inside _synapse_extract_flat_astNameError → swallowed as extraction_script_crash. The inspector was broken for any stage through this transport.

Fix: import hou/json locally inside the function. Verified live — extraction now returns the full /stage AST (17 nodes, json.dumps OK); inspector unit tests stay green (85 passed, 10 live skipped).

2. CI red on master (missing dev deps)

pip install -e ".[dev,websocket,mcp]" then pytest tests/ failed on the Linux runners because the dev extra omitted:

  • pytest-asynciotest_solaris_ordering ("async def functions are not natively supported")
  • numpytest_frame_validator ("No module named 'numpy'")
  • anthropictest_host_layer ("anthropic SDK is not installed" — the vendored SDK is Windows-only binaries, unusable on Linux)

Fix: added all three to the dev extra. CI will confirm.

Known remaining (follow-up)

Platform-specific reds not addressed here (they pass on Windows, fail on the Linux runner): the Windows-only toast test in test_render_notify and a couple of mock-path asserts in test_layout_and_matlib / test_render. These need OS gating, tracked separately.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Fixed PowerShell notification compatibility on Windows systems.
  • Chores

    • Updated development dependencies for CI testing environments.
    • Enhanced internal script reliability for third-party tool integration.
    • Improved test configuration flexibility.

Review Change Stack

…I test deps

inspector: the /stage extraction script runs through the bridge's execute_python,
which execs with split globals/locals -- so the module-level `import hou` / `import
json` were invisible inside `_synapse_extract_flat_ast`, raising NameError that the
top-level handler swallowed as the generic `extraction_script_crash`. Import locally
inside the function. Verified live on 21.0.671: extraction now returns the full
/stage AST (17 nodes, json.dumps OK) where it previously crashed; inspector unit
tests stay green (85 passed).

ci: the `dev` extra was missing test deps the Linux CI runner needs, so
`pytest tests/` failed en masse on master:
  - pytest-asyncio  -> test_solaris_ordering ("async def functions not natively supported")
  - numpy           -> test_frame_validator ("No module named 'numpy'")
  - anthropic       -> test_host_layer ("anthropic SDK is not installed"; the vendored
                       SDK is Windows-only binaries, unusable on the Linux runner)
Added all three to `dev`. Remaining CI reds are platform-specific (Windows-only toast
test, mock-path asserts that diverge Linux-vs-Windows) -- tracked as a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 29, 2026

Warning

Review limit reached

@JosephOIbrahim, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 14 minutes and 16 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 74130a7b-34f8-47c6-b052-bf34a9146046

📥 Commits

Reviewing files that changed from the base of the PR and between 912ccc1 and b2b3b34.

📒 Files selected for processing (4)
  • python/synapse/inspector/tool_inspect_stage.py
  • tests/test_inspect_mock.py
  • tests/test_layout_and_matlib.py
  • tests/test_render.py
📝 Walkthrough

Walkthrough

This PR applies four independent compatibility and robustness improvements across the codebase: adding CI test dependencies and improving test path resolution, ensuring Houdini extraction scripts work in restricted execution environments, and handling potential missing attributes in Windows subprocess operations.

Changes

Compatibility and Robustness Improvements

Layer / File(s) Summary
Test and CI infrastructure updates
pyproject.toml, tests/test_design_system.py
Three CI test dependencies (pytest-asyncio, numpy, anthropic) are added to the dev group with inline documentation. _SYNAPSE_HOME is updated to prefer an existing ~/.synapse/design deployment but fall back to the repository root if unavailable.
Execution environment robustness fixes
python/synapse/inspector/tool_inspect_stage.py, python/synapse/server/render_notify.py
The Houdini extraction script imports hou and json locally inside the function rather than relying on module-level imports to handle Houdini's split globals/locals execution model. Windows subprocess creation flags use getattr() to safely access CREATE_NO_WINDOW, preventing errors if the attribute is unavailable.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 We hop through Windows paths with care,
Houdini scripts now safe to share,
CI deps are set, tests know their home—
Four little fixes, but now more roam! 🌿

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main changes: fixing an inspector crash related to execution scoping and adding missing CI test dependencies. Both are primary objectives of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/inspector-scoping-and-ci-deps

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.

Joseph Ibrahim and others added 6 commits May 29, 2026 18:30
…ast CREATE_NO_WINDOW

test_design_system pointed only at the DEPLOYED base (~/.synapse), which the CI
runner doesn't have -> ~30 failures (ModuleNotFound tokens/synapse_styles,
FileNotFound shelf/panel/installer, "0 SVGs"). Fall back to the REPO source
(design/, houdini/, install.py) when nothing is deployed; identical layout, so
deployed installs are still validated when present.

send_toast used subprocess.CREATE_NO_WINDOW (a Windows-only attribute); on the
Linux runner, with os.name patched to "nt", evaluating it raised AttributeError
before subprocess.run, so the toast tests saw call_args=None. Guard with
getattr(subprocess, "CREATE_NO_WINDOW", 0) -- harmless on Windows, correct on Linux.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_render (4x "an integer is required"): the helper globally patches
pathlib.Path.stat to a bare MagicMock with no st_mode. handlers_render.py:288
runs render_dir_path.mkdir(parents=True, exist_ok=True); on Linux, when the
temp render dir already exists, mkdir's internal is_dir() calls
S_ISDIR(stat().st_mode) -- st_mode is a MagicMock -> "an integer is required".
On Windows the dir didn't pre-exist so stat was never hit. Give the stat mock a
real int st_mode (directory) so is_dir() works; st_size stays for the flush poll.
The handler is correct.

test_layout matlib (2x): handlers_node binds `hou` at import time from
sys.modules["hou"]. In the full suite it gets bound to a different stub than
test_layout's _mock_hou, so patch.object(_mock_hou, "node", ...) never reaches
the handler -> hou.node() returns a default mock -> result["shader_path"] is a
raw createNode().createNode() chain and uv.parm("signature") is never called.
mock_env now rebinds handlers_node.hou to _mock_hou (mirrors the existing
handler_helpers rebind at module load), making the test order-independent.

Both are test-only; production code unchanged. Local: 62 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The previous commit rebned handlers_node.hou (+ HOU_AVAILABLE) via direct
module-global assignment in the mock_env fixture. With no teardown it leaked
into every later test that uses handlers_node -> 14 regressions in
test_network_explain (empty results, 0 == 3) and test_mcp_roundtrip
(hou.node() returned a truthy mock instead of None, so "missing parent" no
longer raised -> True is False).

Scope both rebinds with monkeypatch so they auto-restore after each test.
Verified against the full local suite in CI collection order:
test_render / test_layout / test_network_explain / test_mcp_roundtrip all green.
(The only full-suite-local failures are test_agent_state / test_scene_memory,
which assert the no-pxr path and only fail because this machine has Houdini's
pxr installed; CI has no pxr so they pass there.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
test_flipbook_fallback_on_usdrender_no_output and
test_no_flipbook_fallback_for_non_usdrender patched Path.stat but not
Path.mkdir -- unlike their 3 sibling render tests. handlers_render.py:288 runs
render_dir_path.mkdir(parents=True, exist_ok=True); on Linux when the temp dir
already exists, mkdir's internal is_dir() calls S_ISDIR(stat().st_mode) on the
MagicMock -> "an integer is required". Patch mkdir to a no-op, matching the
sibling tests. Test-only; handler is correct. Local: 2 passed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…names to globals

PR #5 added local `import hou`/`import json` to _synapse_extract_flat_ast, but
that was INCOMPLETE. The bridge execs the extraction script with
exec(code, G, L) where G != L (handlers.py _run_compiled / api_adapter
_run_in_namespace). Top-level defs, imports and constants bind into L, but the
script's functions resolve names via their __globals__ (= G). So from INSIDE
the functions:
  - _synapse_extract_node (a top-level def) is invisible -> _synapse_extract_flat_ast
    crashes at the call site on EVERY scene (NameError -> extraction_script_crash)
  - SCHEMA_VERSION / _MAX_ERR_LEN (top-level consts) are invisible; an errored or
    warned node double-faults on _MAX_ERR_LEN inside its own except handler

The original "json/hou not defined" was merely the FIRST name hit; fixing it
just moved the crash downstream. Confirmed live: synapse_inspect_stage("/stage")
on a clean Cornell Box returned extraction_script_crash.

Fix: after the function defs, re-publish the names the functions need into G
(globals() at the exec'd module level IS G). Drop the now-redundant local
imports and their (disproven) "verified live" comment.

Add tests/test_inspect_mock.py::TestExtractionScriptSplitScope: execs the REAL
template under split globals/locals (hou NOT injected) across clean/errored/
warned nodes. Red against the prior template (NameError _synapse_extract_node),
green now. The transport-mocked tests never exec the real script, so they
missed this entirely.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…+ version-robust)

The render helper added st_mode to the stat mock but -- unlike its sibling
helpers (the flipbook tests and _setup_render) -- never patched Path.mkdir. So
the three tests using it (test_returns_image_path_and_engine,
test_frame_defaults_to_current, test_resolution_override) ran a REAL
mkdir(parents=True, exist_ok=True) against the CI /tmp, creating
/tmp/houdini_temp/.synapse/renders -- a filesystem side effect from a
supposedly pure mock test. On Python 3.14, Path.is_dir() routes through
os.path.isdir (not stat), so the st_mode trick was inert and the tests passed
only because /tmp happened to be writable; on 3.11 they relied on the
FileExistsError->is_dir->S_ISDIR(st_mode) branch. Two different behaviors
across the matrix.

Patch Path.mkdir to a no-op (matching the siblings) and drop the now-inert
st_mode. Hermetic and identical on both 3.11 and 3.14; no FS side effects.

Surfaced by the adversarial pre-merge review (findings #5/#6/#9/#14, all CONFIRMED).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@JosephOIbrahim JosephOIbrahim merged commit 0d72d15 into master May 29, 2026
3 checks passed
@JosephOIbrahim JosephOIbrahim deleted the fix/inspector-scoping-and-ci-deps branch May 29, 2026 23:18
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