Skip to content

feat(web): pickle-safe dynamic relay bridge classes - #3569

Open
paul-nechifor wants to merge 1 commit into
paul/feat/w4-robot-carrierfrom
paul/feat/w5-dynamic-bridge-classes
Open

feat(web): pickle-safe dynamic relay bridge classes#3569
paul-nechifor wants to merge 1 commit into
paul/feat/w4-robot-carrierfrom
paul/feat/w5-dynamic-bridge-classes

Conversation

@paul-nechifor

Copy link
Copy Markdown
Contributor

No description provided.

- make_relay_bridge_class(specs) builds RelayBridgeModule subclasses at
  runtime. A spec is (stream, message type, direction), nothing else.
- DimOS ships module classes through pickle (forkserver deploy,
  Actor.__reduce__). A runtime-built class cannot pickle by reference.
- So the classes get a dedicated metaclass registered with copyreg: pickle
  serializes the port specs and rebuilds the class through the factory.
- The factory is memoized process-wide so repeated unpickles return the
  identical class object (blueprints compare classes with `is`).
- The reducer ships plain field tuples, not spec instances, so a class from a
  reloaded module still repickles cleanly.
- Spec validation rejects reserved or invalid stream ids and names that
  collide with existing RelayBridgeModule attributes.
- Pure addition (dynamic.py + tests). The channel authoring ticket on top of
  this compiles cockpit(channels=...) into such a class.
@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This change introduces deterministic, memoized dynamic RelayBridgeModule classes with validation and pickle support so stream annotations can be reconstructed across process boundaries.

The reload coverage and fresh-worker deployment coverage currently exercise separate flows. The restart path reloads the generated class before deploying it to a fresh Python worker, but no test covers those operations together.

T-Rex validation blocked

The focused reload-then-clean-worker check could not execute because the zenoh Python package was missing from the runtime used by the check. The uploaded evidence references did not include required labels, so they cannot be attached as review artifacts.

Confidence Score: 4/5

The implementation has focused coverage for reload serialization and fresh-worker deployment, but the production sequence combining both remains untested.

The reported issue is limited to test coverage and does not demonstrate a current user-visible failure. Code inspection identifies the uncovered handoff between module reload and worker deployment.

Files Needing Attention: dimos/web/relay_bridge/test_dynamic.py should add a test that reloads the dynamic module before deploying a generated class to a fresh worker.

T-Rex T-Rex Logs

What T-Rex did

  • A focused regression script was prepared to reload a generated RelayBridgeModule class, deploy it through a clean WorkerManagerPython worker, and verify a worker RPC call.
  • Execution stopped before completing the path because the zenoh Python package was not available at runtime, so the test path could not be executed or validated.
  • The approach was documented as blocked for runtime confirmation, and the static verdict is that the exact combined path is absent from the current integration suite.
  • The review lists the relevant locations for the absence of the combined production path, including the test and code areas identified in the proof.

View all artifacts

T-Rex Ran code and verified through T-Rex

Reviews (1): Last reviewed commit: "feat(web): pickle-safe dynamic relay bri..." | Re-trigger Greptile

assert pickle.loads(data) is C, "pre-reload pickle lost identity"
assert pickle.loads(pickle.dumps(C)) is C, "re-pickle after reload failed"
again = mod.make_relay_bridge_class([mod.DynamicPortSpec("reload_feed", Vector3, "rx")])
assert again is C, "factory lost identity after reload"

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.

P2 Reload-to-worker path remains untested

The reload test re-pickles the surviving generated class only in the interpreter where it remains published, while the fresh-worker test does not reload first. This leaves the coordinator's combined reload-plus-clean-worker deployment sequence untested, allowing a regression at that serialization boundary to pass the suite.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
4336 1 4335 176
View the top 1 failed test(s) by shortest run time
dimos.codebase_checks.test_no_sections::test_no_section_markers
Stack Traces | 0.764s run time
def test_no_section_markers():
        """
        Fail if any file contains section-style comment markers.
    
        If a file is too complicated to be understood without sections, then the
        sections should be files. We don't need "subfiles".
        """
        violations = find_section_markers()
        if violations:
            report_lines = [
                f"Found {len(violations)} section marker(s). "
                "If a file is too complicated to be understood without sections, "
                'then the sections should be files. We don\'t need "subfiles".',
                "",
            ]
            for path, lineno, text in violations:
                report_lines.append(f"  {path}:{lineno}: {text.strip()}")
>           raise AssertionError("\n".join(report_lines))
E           AssertionError: Found 2 section marker(s). If a file is too complicated to be understood without sections, then the sections should be files. We don't need "subfiles".
E           
E             .../web/relay_bridge/test_relay_bridge_module.py:1208: # --- Teleop (the tele_cmd_vel tx channel) ---
E             .../web/relay_bridge/test_relay_bridge_e2e.py:401: # --- Teleop e2e: viewer datagrams -> relay lease gate -> bridge publishes ---

lineno     = 401
path       = '.../web/relay_bridge/test_relay_bridge_e2e.py'
report_lines = ['Found 2 section marker(s). If a file is too complicated to be understood without sections, then the sections should ...y_bridge/test_relay_bridge_e2e.py:401: # --- Teleop e2e: viewer datagrams -> relay lease gate -> bridge publishes ---']
text       = '# --- Teleop e2e: viewer datagrams -> relay lease gate -> bridge publishes ---'
violations = [('.../web/relay_bridge/test_relay_bridge_module.py', 1208, '# --- Teleop (the tele_cmd_vel tx channel) ---'), ('dim...idge/test_relay_bridge_e2e.py', 401, '# --- Teleop e2e: viewer datagrams -> relay lease gate -> bridge publishes ---')]

dimos/codebase_checks/test_no_sections.py:145: AssertionError

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

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