Skip to content

Hop labels use min-hop semantics even when min_hops filters shorter paths #878

Description

@lmeyerov

Summary

When using min_hops to filter paths, hop labels still use "first seen" (minimum hop) semantics. This causes nodes reachable via multiple path lengths to be labeled with the shortest path's hop distance, even when that shorter path is filtered out by min_hops.

Reproduction

nodes = [{"id": x} for x in ["a", "b", "c", "d", "x"]]
edges = [
    {"edge_id": "e1", "src": "a", "dst": "b"},
    {"edge_id": "e2", "src": "b", "dst": "c"},
    {"edge_id": "e3", "src": "c", "dst": "d"},
    {"edge_id": "short1", "src": "a", "dst": "x"},
    {"edge_id": "short2", "src": "x", "dst": "d"},
]
# Graph has two paths from a to d:
#   - Long path: a→b→c→d (3 hops)
#   - Short path: a→x→d (2 hops)

ops = [
    n({"id": "a"}),
    e_forward(min_hops=3, max_hops=3, label_node_hops="hop"),
    n(),
]
# With min_hops=3, only the long path is valid
# Expected: node d labeled with hop=3
# Actual: node d labeled with hop=2 (from filtered-out short path)

Root Cause

The hop labeling logic in hop.py tracks minimum hop distance per node (groupby().min() pattern). This is correct for display purposes when all paths are valid, but incorrect when min_hops filters out shorter paths.

The Yannakakis semijoin pruning correctly excludes edges not on valid paths, but the hop labels are computed before/independently of this filtering.

Impact

  • Hop labels may show incorrect distances when min_hops > 1
  • This is a display/labeling issue only - path validity and edge filtering are correct

Failing Test

tests/gfql/ref/test_enumerator_parity.py::TestTrickyHopBounds::test_branching_path_lengths

Related

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions