Skip to content

[codex] Reconstruct rerun TF trees in the bridge#1881

Open
skorinko wants to merge 2 commits intodimensionalOS:mainfrom
skorinko:codex-rerun-tf-tree
Open

[codex] Reconstruct rerun TF trees in the bridge#1881
skorinko wants to merge 2 commits intodimensionalOS:mainfrom
skorinko:codex-rerun-tf-tree

Conversation

@skorinko
Copy link
Copy Markdown

Summary

  • teach MultiTBuffer to publish transform updates and reconstruct hierarchical frame chains
  • make RerunBridgeModule own a TF buffer and log /tf messages at reconstructed Rerun entity paths
  • add focused tests for TF subscriptions, path reconstruction, and rerun bridge TF interception

Why

Standalone rerun-bridge was logging TF updates as flat child-frame paths, so the viewer could not reconstruct the real TF tree unless a blueprint hardcoded extra TF-specific visualization setup.

Impact

rerun-bridge now reconstructs TF entity paths internally from the buffered transform graph, which makes standalone visualization behave more like the rest of the TF stack and removes the need for callers to rely on partial TF message layout.

Validation

  • ruff check dimos/protocol/tf/tf.py dimos/protocol/tf/test_tf.py dimos/visualization/rerun/bridge.py dimos/visualization/rerun/test_bridge_tf.py
  • focused pytest run for the new TF buffer and rerun bridge tests (with repo autoconf stubbed to avoid sandbox-only system prompts)

Closes #1627

@skorinko skorinko marked this pull request as ready for review April 18, 2026 16:58
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 18, 2026

Greptile Summary

This PR teaches MultiTBuffer to publish transform updates via a subscriber pattern and adds get_frame_chain/entity_path_for_frame so RerunBridgeModule can intercept /tf messages and log each transform at its fully-reconstructed hierarchical entity path instead of a flat child-frame path.

  • P1 (dimos/protocol/tf/tf.py line 138–139): receive_transform iterates self._subscribers in-place; a callback that calls unsubscribe() mutates the list mid-loop, silently skipping the next registered callback. A defensive copy (list(self._subscribers)) before the loop is the minimal fix.

Confidence Score: 4/5

Safe to merge after fixing the subscriber list mutation bug; the remaining findings are minor style or edge-case concerns.

One P1 bug exists: mutating self._subscribers during iteration in receive_transform can silently drop callbacks when any subscriber unsubscribes itself during dispatch. The root_frame mismatch in entity_path_for_frame is a P2 edge case for non-world-rooted trees. All other findings are style or test-fragility concerns.

dimos/protocol/tf/tf.py — receive_transform subscriber iteration and entity_path_for_frame root-frame stripping logic.

Important Files Changed

Filename Overview
dimos/protocol/tf/tf.py Adds subscriber pub/sub pattern to MultiTBuffer, get_parent_transform, get_frame_chain, entity_path_for_frame, and receive_tfmessage; contains a list-mutation-during-iteration bug in receive_transform and a silent wrong-path edge case in entity_path_for_frame.
dimos/visualization/rerun/bridge.py Adds TF interception in _on_message, owns a MultiTBuffer, and reconstructs hierarchical entity paths via entity_path_for_frame before logging; logic is clean with lazy rerun import.
dimos/protocol/tf/test_tf.py Adds focused tests for subscribe/unsubscribe and get_frame_chain/entity_path_for_frame; coverage is good for the happy path.
dimos/visualization/rerun/test_bridge_tf.py New integration test for TF path reconstruction in the bridge; bypasses start() lifecycle via direct attribute assignment, which is fragile if the test is ever refactored to call start().

Sequence Diagram

sequenceDiagram
    participant PubSub
    participant Bridge as RerunBridgeModule
    participant TFBuf as MultiTBuffer
    participant Rerun

    PubSub->>Bridge: _on_message(TFMessage, "/tf")
    Bridge->>Bridge: _is_tf_message() → true
    Bridge->>TFBuf: receive_tfmessage(msg)
    loop for each Transform in TFMessage
        TFBuf->>TFBuf: store in buffers[parent, child]
        TFBuf->>Bridge: _log_tf_transform(transform) [subscriber]
        Bridge->>TFBuf: entity_path_for_frame(child_frame_id)
        TFBuf->>TFBuf: get_frame_chain() [BFS up parents]
        TFBuf-->>Bridge: "world/tf/robot/camera"
        Bridge->>Rerun: rr.log("world/tf/robot/camera", transform.to_rerun())
    end
Loading

Reviews (1): Last reviewed commit: "Reconstruct rerun TF trees in bridge" | Re-trigger Greptile

Comment thread dimos/protocol/tf/tf.py Outdated
Comment thread dimos/visualization/rerun/test_bridge_tf.py
Comment thread dimos/protocol/tf/tf.py
- MultiTBuffer.receive_transform: snapshot subscribers before dispatch so a
  callback that unsubscribes itself doesn't skip the next subscriber.
- RerunBridgeModule.start: treat _tf_buffer as an injection point — skip
  creation and subscription when it's already set, so tests that preinstall
  it aren't silently clobbered if start() is ever invoked.
- MultiTBuffer.entity_path_for_frame: when root_frame is set, strip the
  topmost frame unconditionally. It's either the matched root_frame or the
  tree's actual root; either way it's represented by `prefix`. Prevents
  paths like world/tf/map/robot when the tree isn't rooted at "world".
- Add regression tests for all three behaviors.
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.

Rerun Bridge should reconstruct the tf tree automatically

1 participant