Repository navigation
feat(query): --seed to start the traversal at given nodes - #4289
devkancheti4-design wants to merge 3 commits into
Conversation
|
Thanks for the pull request, @devkancheti4-design. A maintainer will review it soon. Want to talk it through while it is in review? Come join us on our Discord server. For longer-form discussion there is also GitHub Discussions. A couple of things that speed up review: make sure the test suite passes on Python 3.10 and 3.13, and that the change keeps extraction deterministic. |
There was a problem hiding this comment.
Graphify reviewed this change.
No issues found by static checks — no coupling regressions or blocking issues in the code graph. That is not the same as safe to merge: see what was not checked.
Not checked: tests were not run; formal verification proved 0 of 3 changed function(s) (2 sampled, not proven, 1 not verified).
Formal verification. PR-changed functions: 2/3 verified (0 proven, 2 may-equivalent, 0 distinguished) · 1 not verified (1 vacuous).
Not verified on this run: dispatch\_command (vacuous: never exercised).
Graphify review — findings
Adds a repeatable --seed X flag to graphify query so an external ranker can pick the traversal's start nodes instead of the question's keyword matches. Each seed resolves like affected does (node id, unique label, or file path anchored at the graph's repo root rather than CWD). Seeds that don't match exactly one node are listed as skipped in the header, and if none resolve the query returns an error rather than falling back to keyword seeds.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 763 functions depend on the 246 functions this change touches.
Health — this change adds coupling hotspots:
- worse:
main()— 105 callers, 3 callees - worse:
dispatch_command()— 2 callers, 131 callees - new:
_render_query()— 1 callers, 7 callees
Verification — 763 functions in the blast radius were not formally verified this run (proofs are advisory here).
Gate & verification
graphify gate
PASS — objectively clean (no health regressions, tests not run — proofs not run this pass (advisory)). Grounded, not self-assessed.
Advisory (not blocking):
- verification_scope: 763 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
40 of 362 test file(s) selected (11%) via static blast radius.
tests/test_affected_cli.py— impacttests/test_agents_platform.py— impacttests/test_benchmark.py— impacttests/test_benchmark_raw_graph.py— impacttests/test_cloud_cta.py— impacttests/test_codebuddy.py— impacttests/test_dedup_shrink_refuses_force_write.py— impacttests/test_devin.py— impacttests/test_explain_cli.py— impacttests/test_extract_cli.py— impacttests/test_file_label_disambiguation.py— impacttests/test_global_add_tag_inference.py— impacttests/test_god_nodes_cli.py— impacttests/test_hollow_chunks_arm_shrink_guard.py— impacttests/test_hook_guard_token_match.py— impacttests/test_hook_out_of_project_paths.py— impacttests/test_hook_strict.py— impacttests/test_incomplete_build_guard.py— impacttests/test_install.py— impacttests/test_install_references.py— impacttests/test_install_version_warning.py— impacttests/test_mcp_graph_view_cache.py— impacttests/test_merge_chunks_validation.py— impacttests/test_multigraph_diagnostics.py— impacttests/test_no_dedup_flag.py— impacttests/test_opencode_plugin_refresh.py— impacttests/test_partial_cache.py— impacttests/test_path_cli.py— impacttests/test_query_cli.py— impacttests/test_query_induced_edges.py— impacttests/test_query_mcp_direction.py— impacttests/test_query_names_its_graph.py— impacttests/test_query_seeds.py— impact, changed-testtests/test_serve.py— impacttests/test_serve_http.py— impacttests/test_skill_auto_refresh.py— impacttests/test_skill_version_warning.py— impacttests/test_stale_prune.py— impacttests/test_terraform.py— impacttests/test_unverified_semantic_shrink.py— impact
Selection is safe under the controlled-regression assumption; always-run tests + a periodic full run are the backstops. Advisory — it never changes the check verdict.
Formal verification
No difference found (not proven): No behavior difference found in \_run\_cli (not a proof).
The verifier ran both versions of \_run\_cli on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
Could not verify: Could not verify dispatch\_command.
The verifier did not have enough to check dispatch\_command, so it is saying so rather than guessing. No false assurance is the whole point.
Guarantee: No guarantee either way, this is an honest abstention, not a pass.
Note: Reason: no capturable inputs from the test suite; property tier: not verifiable: all 40 sampled inputs raised on both versions — the function never executed, so 'no divergence' would be vacuous (mostly SystemExit — names the real obstacle, not a sampling gap)
No difference found (not proven): No behavior difference found in \_query\_graph\_text (not a proof).
The verifier ran both versions of \_query\_graph\_text on many inputs and saw identical behavior every time. Strong evidence the change is safe, but evidence, not a proof.
Guarantee: Empirical: differential testing (both versions run on many generated inputs). A divergence on an untested input remains possible, so this is 'no counterexample found', not 'proven equivalent'.
Note: An input the sampler did not try could still differ.
· 1 grounded finding(s) anchored inline below; 2 more finding(s) on lines outside this diff (see the check run).
| context_filters=context_filters, graph_path=graph_path) | ||
|
|
||
|
|
||
| def _render_query( |
There was a problem hiding this comment.
_render_query()
fans out to 7 callees (efferent coupling).
Grounded coupling-delta finding (deterministic), not an LLM guess.
|
Thanks for the quick automated review. Python 3.10 and 3.13: About the |
|
Thanks for the clean PR — this is a useful escape hatch for the recurring seed-selection issues, and reusing Verification
No blocking bugs. A few small things that would make it perfect:
Optional nits: the quotes on |
|
Thanks for taking the time to review this, @nothariharan! The latest commit is up. |
|
Thanks @devkancheti4-design — the Could you rebase onto current v8, carry |
An external ranker (embeddings, a hybrid or learned retriever, or an agent that already knows the file) can choose where graphify query starts instead of the question's keyword matches; the graph then does the expansion. Each --seed value resolves exactly as affected resolves its seed (affected.resolve_seed: node id, unique label, callable name, repo-relative or absolute file path anchored to the graph's root), so there is one interpretation of a node reference. Fail closed: a value that does not resolve to exactly one node is reported and skipped; if none resolve, the query says so and does not fall back to keyword seeds. Without --seed the output is unchanged (rendering moved into _render_query as is). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ved seed once; log seeds - graphify query --seed with no value (trailing --seed or --seed=) now exits with an error instead of running a keyword query. - An unresolved seed given twice is listed once. - The query log records the seeds used. - Tests: the callable form (name and name()), --seed with --context, both no-value forms, and the logged seeds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cation The seeded path hands the resolved nodes to _subgraph_to_text as seeds (seeds=start_nodes, the BUG2 fix), so the given seed is the first NODE line and still shows under a small token budget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
d3aeaaa to
67f65c4
Compare
|
Thanks @safishamsi! Rebased onto current v8 (0.9.86):
Tests:
|
What does this PR do?
Resolves #4293 (related: #445, #2381, #2384, #3810).
This PR adds
--seed X(repeatable) tographify query. The caller can choose where the traversal starts instead ofusing the question's keyword matches. The use case: an external ranker picks where to start, and graphify's graph does
the expansion. The ranker could be embeddings, a hybrid or learned retriever, or an agent that already knows the
relevant file. This is the same retrieve-then-expand shape that
BENCHMARKS.mddescribes for graph-expand, exposed onthe CLI.
Behaviour:
affectedresolves its seed(
affected.resolve_seed): node id, unique label, callable name with or without(), or a repo-relative or absolutefile path. An absolute path is anchored to the graph's own root, using the same derivation as
affected(affectedsilently returns nothing when the path is spelled differently (./ or absolute) #2706), soit works from any cwd.
Unresolved seeds (skipped). If none resolve, the command printsNo unique node match for --seed: ...and doesnot fall back to keyword seeds.
Start (given): [...]. Seeds are deduplicated, keeping their order. Context filters,--budgetand BFS/DFS are unchanged.--seed. The output is unchanged: rendering moved into_render_queryas is.Not in this PR (happy to follow up if wanted):
query_graphparameter;skillgen --bless);Context: I work on a code retrieval layer and wanted to hand graphify its top files as start points. The option is
generic and contains no external code.
Type of change
Verification & Invariants
Invariants:
No new way to interpret a node reference: it reuses
resolve_seed.Ambiguity fails closed, with no guessing and no silent fallback.
The default
querypath is unchanged.No persisted or generated state is touched.
Read the CONTRIBUTING.md guide.
Reproduced the issue and identified the invariant. (n/a, this is a feature; the invariants are above)
Made the smallest fix necessary.
Added a regression test (if bug fix) or isolated boundary test.
Kept the PR description synchronized with the final implementation.
Documented any limitations / unsupported cases explicitly.
How was this tested?
Complete pass (
uv run pytest -q -rf tests --deselect tests/test_skillgen.py::test_audit_coverage_passes):6,876 passed, 168 skipped, 8 failed. All 8 failures are in
tests/test_skillgen.py. The deselectedtest_audit_coverage_passesfailed the same way in an earlier run, which makes 9 in all:test_audit_coverage_passestest_all_progressive_hosts_check_and_audit_cleantest_monolith_roundtrip_passes_for_aider_and_devintest_monoliths_change_only_sanctioned_linestest_always_on_roundtrip_is_byte_faithfultest_audit_catches_an_induced_per_host_droptest_audit_catches_a_dropped_non_allowlisted_headingtest_amp_audit_coverage_passes_against_its_own_v8test_agents_audit_baseline_is_amps_v8_bodyEach of the 9 fails identically on unmodified
v8in my environment, because my clone is shallow and these tests readolder git refs (
could not read <sha>:graphify/skill.md). The failures are not related to this change. No other testfails.
New tests (
tests/test_query_seeds.py):Graphify-specific checklist
uv run python -m tools.skillgen --bless) when changing their source fragments. (n/a, no fragments changed)resolve_seedfor comparison.🤖 Generated with Claude Code