Skip to content

feat(common): archive tracked nodes absent from an update round (+ propagate archived attrs to the backend)#156

Draft
harelb wants to merge 3 commits into
MIT-SPARK:developfrom
harelb:feat/archive-missing-tracks
Draft

feat(common): archive tracked nodes absent from an update round (+ propagate archived attrs to the backend)#156
harelb wants to merge 3 commits into
MIT-SPARK:developfrom
harelb:feat/archive-missing-tracks

Conversation

@harelb

@harelb harelb commented Jul 8, 2026

Copy link
Copy Markdown

Problem (two halves of one lifecycle gap)

1. Track-driven nodes never archive. GraphUpdater stamps is_active=true on every add/update of a tracked node and nothing ever clears it (places/frontiers have explicit archival; track-driven layers don't). Consequence: Pairwise::candidates filters to !is_active, so backend merge proposals for such layers are structurally empty — object dedup can never fire. Measured on a 38-min indoor bag: 144/144 object nodes still active at shutdown, zero merges ever, in every run.

2. Archived copies are frozen forever. Once a downstream copy of a node is inactive, mergeGraph skips its attribute updates (scene_graph_layer.cpp archived gate) — and since is_active itself only updates via that same clone, the copy can never be reactivated. Any attribute written after archival (e.g. an extractor finalizing a node after its track leaves the active window) silently never reaches the backend.

Fix

  • LayerTracker::Config::archive_missing (default false — no behavior change unless opted in): tracked nodes absent from a layer's update round get is_active=false; a returning track re-activates via the normal update path. Unit tests included.
  • The frontend→backend and backend-ingest mergeGraph calls set GraphMergeConfig::update_archived_attributes = true, so late attribute updates reach the backend mirror regardless of archival state.

Measured (fork, with archive_missing: true for objects)

Under a real 235-edge loop-closure stream: 11 duplicate objects merged by the existing backend merge machinery (previously structurally impossible), map quality unchanged (objects-on-mesh median 0.11 m).

Notes: exposed a latent MergeTracker crash once merges started firing — fixed separately in #155. Orthogonal to #153/#154.

harelb added 3 commits July 8, 2026 16:14
Object nodes arrived is_active=true and nothing ever cleared the flag,
so Pairwise merge candidates (archived-only) were always empty and
backend object merges could never fire (box_6/7: 144/144 active).
Opt-in per layer via LayerTracker archive_missing (default false).
Second hop of the same gate: graph_builder's frontend->backend_graph
mergeGraph also skipped archived-node attribute updates, so the
extractor's image_folder still never left the frontend (box_10: hook
saw empty attrs, 0 renames).
Same gate as the frontend hop: mergeGraph skips attribute updates for
archived target copies, so attributes written after a node archives
never reached the backend's odometric mirror.

@nathanhhughes nathanhhughes left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm skeptical that this is useful; this is what I use to control whether or not objects should be archived (it defaults false because it messes with how the original Hydra mesh-based objects work but should be true in your case). Two reasons why this should be somewhere else:

  • Archiving nodes that are missing from an update constrains how the active window behaves and/or makes it impossible to have two sources updating the same layer (which is not the end of the world, but seems not worth it if we don't need to do it this way)
  • The archival / active window logic of whatever is sending the graph update may not be the same as the archival / active window logic of the frontend, and the frontend should have final say about what should still be active

Comment on lines +349 to +353
// archived nodes still receive attribute updates (e.g. the object extractor's
// image_folder lands after the track archives) that the backend must see
GraphMergeConfig merge_config;
merge_config.update_archived_attributes = true;
state_->backend_graph->graph->mergeGraph(*dsg_->graph, merge_config);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This is way more expensive for no benefit. mergeGraph copies in attributes while the destination is active, so the last update to attributes (when is_active is flipped to false) is always caught. This is actually how is_active flips from true to false in the backend (so a lot more things would be broken if this didn't work)

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.

2 participants