Skip to content

fix(flow): follow kafka topics + rename --max-hops to --depth#396

Merged
HumanBean17 merged 3 commits into
masterfrom
fix/flow-kafka-depth
Jul 7, 2026
Merged

fix(flow): follow kafka topics + rename --max-hops to --depth#396
HumanBean17 merged 3 commits into
masterfrom
fix/flow-kafka-depth

Conversation

@HumanBean17

@HumanBean17 HumanBean17 commented Jul 6, 2026

Copy link
Copy Markdown
Owner

Problem

Consumer report: jrag flow (1) does not follow kafka even when the route exists, and (2) has no --depth flag.

Root cause

Kafka: _resolve_route_candidates matched only on path/path_template, but kafka_topic Routes carry their name in topic (with path=""). So jrag flow <topic> died at the resolve step (status=none) before reaching trace_request_flow — even though the backend already supported kafka (async inbound via ASYNC_CALLS/topic + outbound via EXPOSES). Asymmetric with _resolve_producer_candidates, which already matches p.topic.

--depth: flow exposed --max-hops while every sibling traversal (callers/callees/impact/decompose) uses --depth, so jrag flow '/x' --depth 3 errored with "unrecognized arguments".

Changes

Commit 1 — fix(resolve)

  • Add route_topic + route_topic_prefix to ResolveReason / VALID_RESOLVE_REASONS (java_ontology.py).
  • Add r.topic exact + prefix queries to _resolve_route_candidates, mirroring the producer resolver (resolve_service.py). _drop_route_mirrors already collapses the no-EXPOSES producer phantom onto the @KafkaListener server route (kafka fqn='' groups them).

Commit 2 — feat(flow)

  • Rename --max-hops--depth (dest=depth, default 5); keep --max-hops as a hidden back-compat alias. The query positional now also accepts a Kafka topic name.

Commit 3 — test(flow) (review follow-up)

  • Strengthen tests so they prove the user-reported behavior, not just parsing/resolution (see Tests).

The Python API param trace_request_flow(..., max_hops=...) is intentionally left as-is — internal kwarg, not a user-facing flag.

Scope of the resolver fix

The resolver is shared, so the fix reaches beyond flow:

  • flow <topic> — fully works (inbound producers + outbound CALLS). ✅
  • callers <topic> — works via --kind route. Behavior change: a topic with both a Producer and a server Route is now genuinely ambiguous without --kind (previously only the Producer matched, which then errored because callers only accepts Symbol/Route roots). --kind route is the disambiguation that runs find_route_callers.
  • overview <topic> — only overview --as route <topic> benefits; the bare form auto-detects the subject as a topic and routes to the topic view, not the route resolver.

Tests (6 total)

  • test_resolve_service_route_kafka_topic — consumer-only topic resolves to one Route (was none before the fix).
  • test_resolve_service_route_kafka_topic_drops_producer_mirror — producer+consumer topic collapses to the single server Route.
  • test_resolve_every_reason_in_closed_set_appears — extended with a kafka row + r.topic mock branches.
  • test_flow_follows_kafka_topic_on_fixturejrag flow <topic> end-to-end; asserts a non-empty follow graph with a kafka-specific ASYNC_CALLS edge (proves following, not just resolution).
  • test_flow_depth_flag_and_max_hops_alias--depth works, --max-hops alias preserved, and --depth actually changes traversal size (depth 1 ≪ depth 5).
  • test_callers_topic_disambiguates_with_kind — documents the dual-sided-topic ambiguity + --kind route recovery.

Verification

  • Full suite: 1134 passed, 14 skipped.
  • ruff: changed files clean (one pre-existing F821 at jrag.py:1644 is unrelated and present on master).

Known limitations / follow-ups (out of scope here)

  • _drop_route_mirrors groups routes by fqn, which is "" for every kafka topic. Verified correct for all realizable cases (phantoms are dead-end artifacts that should be dropped; exposed server routes for distinct topics both survive since both carry EXPOSES; Producers are untouched). A future non-kafka route kind with empty method+path could mis-group — hardening the grouping key is a cheap follow-up if such a kind is ever added.
  • Pre-existing producer priority inversion (producer_topic_prefix=1 but producer_topic=3 — exact ranks below prefix) is a separate latent bug on the producer side; not introduced or touched here. Worth its own ticket.

🤖 Generated with Claude Code

HumanBean17 and others added 3 commits July 7, 2026 00:22
_resolve_route_candidates matched only on path/path_template, so
kafka_topic Routes (name in `topic`, `path=''`) were unresolvable by
name. `jrag flow <topic>` / `callers <topic>` / `overview <topic>`
returned 'none' even though the route + EXPOSES edge existed, while
trace_request_flow already supported kafka end-to-end (async inbound
via ASYNC_CALLS/topic + outbound via EXPOSES).

Add r.topic exact + prefix queries mirroring _resolve_producer_candidates
(new route_topic / route_topic_prefix reasons). _drop_route_mirrors
already collapses the no-EXPOSES producer phantom onto the @KafkaListener
server route (kafka fqn='' groups them), so a producer+consumer topic
resolves to the single server route.

Co-Authored-By: Claude <noreply@anthropic.com>
Rename flow's hop-count flag to --depth so it matches callers/callees/
impact/decompose. --max-hops is kept as a hidden back-compat alias
(argparse.SUPPRESS, same dest=depth). The query positional now also
accepts a Kafka topic name, made reachable by the resolver fix.

Co-Authored-By: Claude <noreply@anthropic.com>
…iguation

Address code-review feedback (test-coverage gaps; no behavior change):

- test_flow_follows_kafka_topic_on_fixture now uses banking.chat.incoming
  (producer + listener) and asserts a non-empty follow graph WITH an
  ASYNC_CALLS edge — the previous compliance.review target has an empty
  listener body, so it only proved resolution, not that flow follows kafka.
- test_flow_depth_flag_and_max_hops_alias now also asserts --depth 1 yields
  strictly fewer edges than --depth 5 (proves the flag affects traversal,
  not just parses).
- New test_callers_topic_disambiguates_with_kind: documents that a dual-sided
  topic (producer + route) resolves ambiguously without --kind, and that
  --kind route is the working disambiguation for callers (callers rejects a
  producer root; use the `producers` command for that view).

Co-Authored-By: Claude <noreply@anthropic.com>
@HumanBean17 HumanBean17 merged commit 73d788e into master Jul 7, 2026
3 checks passed
@HumanBean17 HumanBean17 deleted the fix/flow-kafka-depth branch July 7, 2026 04:10
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