Skip to content

fix(graph): correct TESTED_BY edge direction in tests_for queries#527

Open
Devilthelegend wants to merge 4 commits into
tirth8205:mainfrom
Devilthelegend:fix/515-tested-by-direction
Open

fix(graph): correct TESTED_BY edge direction in tests_for queries#527
Devilthelegend wants to merge 4 commits into
tirth8205:mainfrom
Devilthelegend:fix/515-tested-by-direction

Conversation

@Devilthelegend

@Devilthelegend Devilthelegend commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

Summary

query_graph(pattern="tests_for") traversed TESTED_BY edges in the wrong direction. The parser stores these edges as source = production node, target = test node, but three sites in the code looked them up as if the direction were reversed:

  1. code_review_graph/tools/query.py — the MCP-facing tests_for branch.
  2. code_review_graph/graph.py::get_transitive_tests — three SQL queries (direct match, bare-name fallback, transitive via CALLS).
  3. code_review_graph/graph.py::load_flow_adjacency — the has_tested_by set was populated with test nodes instead of production nodes, corrupting criticality scoring's coverage-gap detection.

Because query_graph falls back to a naming-convention search (test_<name> / Test<name>) when no edges match, the bug was silently masked for tests following standard naming. It surfaced for users whose tests had unconventional names or whose test discovery relied on the underlying edges.

Fix

Flipped the traversal direction in all three places so that for a production node qn:

  • Edges are looked up as source_qualified = qn.
  • The matching test node is read from target_qualified.

For load_flow_adjacency, has_tested_by.add(src) so the set represents production nodes that have at least one test covering them — which is what flows.compute_criticality expects when checking for coverage gaps.

Tests

Added three regression tests that deliberately use unconventional test names (verify_addition, verify_compute, verify_combine_behaviour) so the naming-convention fallback cannot mask future regressions:

  • tests/test_graph.py::TestGraphStore::test_get_transitive_tests_follows_direct_tested_by_edge
  • tests/test_graph.py::TestGraphStore::test_get_transitive_tests_follows_calls_then_tested_by
  • tests/test_tools.py::TestQueryGraphTestsFor::test_query_graph_tests_for_finds_direct_edge

All three pass locally. The broader test_graph.py, test_tools.py, and test_flows.py suites show no real-test regressions (only pre-existing Windows SQLite teardown PermissionErrors, which affect every test in those classes).

Blast radius

Component Before After
query_graph(pattern="tests_for") Wrong results / empty + naming-convention fallback Correct direct lookup
get_transitive_tests (used by review context, hints, criticality) Wrong direction at every hop Correct
compute_criticality coverage-gap detection All flows scored as under-tested Reflects real coverage
Naming-convention fallback Kept as belt-and-braces Kept

Fixes #515

The parser stores TESTED_BY edges as source=production, target=test, but
query_graph(pattern="tests_for"), get_transitive_tests, and
load_flow_adjacency all traversed them in the wrong direction. The
naming-convention fallback (test_<name>/Test<name>) silently masked the
bug for tests following standard naming.

Changes:
- tools/query.py: flip tests_for branch to use get_edges_by_source +
  e.target_qualified
- graph.py::get_transitive_tests: flip three SQL queries to select
  target_qualified where source_qualified = ?
- graph.py::load_flow_adjacency: track production node (src) in
  has_tested_by so criticality scoring reflects real coverage

Regression tests use unconventional test names so the naming-convention
fallback cannot mask future regressions.

Fixes tirth8205#515
Follow-up to the initial fix for tirth8205#515. The earlier patch updated only
the tests_for query, but two other production sites and several test
fixtures still assumed the inverted direction. Those bugs cancelled
each other in the test suite, so the regression only surfaced after
fixing the original site.

Production code:
- changes.py: analyze_changes() now uses get_edges_by_source() when
  detecting test gaps so changed production functions correctly find
  their TESTED_BY edges.
- enrich.py: symbol enrichment now traverses TESTED_BY edges by source
  and reads the target qualified name to surface real test references.

Test fixtures: flip source/target on TESTED_BY edges in
tests/test_changes.py, tests/test_enrich.py, and tests/test_graph.py
to match the canonical Production -> Test direction.
@Devilthelegend

Copy link
Copy Markdown
Contributor Author

All 9 actual checks are green. The pending "expected" status looks like a stale required-context entry in branch protection — could you take a look when you get a chance?

@tirth8205

Copy link
Copy Markdown
Owner

Thanks @Devilthelegend — thorough work. I applied and tested locally: all five inverted consumer sites are fixed (including enrich.py and load_flow_adjacency, which my own audit missed), the already-correct readers in analysis.py/build.py/review.py were rightly left alone, your three regression tests fail on main and pass with the fix, and the full suite is green (1277 passed). Since only the parser writes TESTED_BY edges, existing DBs need no migration — good that this is read-side only.

One ask before merge: the producer side of the contract is still unpinned. test_parser.py::test_tested_by_edges_generated only asserts edges exist, not direction — a future parser flip would pass your new tests (they hand-insert edges) and silently reintroduce #515. Either assert source=production/target=test there, or add one end-to-end parse -> store -> get_transitive_tests test.

Non-blocking: refactor.py:495-507 still reads TESTED_BY by target — inert today (shadowed by companion CALLS edges) but worth a follow-up issue. The stale "expected" status check was a branch-protection misconfiguration on my side (a required context named "CI" that no job reports) — being fixed.

Devilthelegend and others added 2 commits June 11, 2026 08:44
)

Existing parser tests only asserted that TESTED_BY edges exist (len >= 1), not which way they point. That left a gap where the parser could silently revert to the inverted direction and every consumer-side regression test would still pass.

Lock the canonical direction at the producer: source=production, target=test (reads as 'X is tested by Y'). This is the direction the parser already writes and that the consumer-side fixes in this PR now query against.

Requested in maintainer review on tirth8205#527.
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.

Bug: tests_for query uses wrong edge direction for TESTED_BY, always falls back to naming convention

2 participants