perf(detect): scope nested ignore patterns to active subtree - #3535
DevChiniwala wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Graphify reviewed this change.
Looks safe to merge — no coupling regressions and no blocking issues, checked against the code graph (not a self-assessment).
Formal verification. No changes could be formally verified in this run.
Graphify review — findings
Scopes nested .graphifyignore/.gitignore rules to the active root-to-directory branch during detect(), so each ignore check scans only the ancestor chain plus the current directory's own rules instead of an ever-growing list that accumulates every completed sibling subtree's patterns (#2834). During the topdown walk, _activate_walk_directory pops rules from subtrees no longer on the current path and appends the entered directory's own rules, while the later per-file pass reconstructs each file's ancestor chain via _patterns_for_directory (memoized by containing directory) and clears the ignore caches first since directory-pruning results were computed against a different active branch. graphifyignore_patterns in the result now reports the total rules loaded across the whole scan rather than the momentary active count.
No blocking issues surfaced. 7 lower-confidence candidates did not survive cross-model review.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 2624 functions depend on the 735 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract()— 589 callers, 44 callees - new:
_rebuild_code()— 116 callers, 51 callees - new:
detect()— 112 callers, 16 callees - new:
_extract_generic()— 18 callers, 26 callees - new:
save_manifest()— 40 callers, 11 callees - new:
extract_files_direct()— 17 callers, 20 callees - new:
extract_js()— 85 callers, 4 callees - new:
extract_xaml()— 19 callers, 17 callees - …and 44 more — each is listed as a finding
Verification — 2624 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: 1175 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
275 of 275 test file(s) selected (100%) via static blast radius.
Escalated to a full run for safety — the selection is not trustworthy on its own (see below). CI should run the whole suite.
tests/test_affected_cli.py— full-run-safetytests/test_affected_member_seed.py— full-run-safetytests/test_agents_platform.py— full-run-safetytests/test_analyze.py— full-run-safetytests/test_anthropic_custom_endpoint.py— full-run-safetytests/test_antigravity_install.py— full-run-safetytests/test_apm_fallback_version.py— full-run-safetytests/test_architecture_doc.py— full-run-safetytests/test_astro_extraction.py— impact, full-run-safetytests/test_astro_import_ids.py— full-run-safetytests/test_atomic_canvas_export.py— full-run-safetytests/test_atomic_version_stamp.py— full-run-safetytests/test_atomic_writes.py— impact, full-run-safetytests/test_backend_env_isolation.py— full-run-safetytests/test_backend_extras.py— full-run-safetytests/test_benchmark.py— full-run-safetytests/test_benchmark_raw_graph.py— full-run-safetytests/test_build.py— impact, full-run-safetytests/test_build_merge_dedup_scope.py— full-run-safetytests/test_build_merge_hyperedges_and_prune.py— full-run-safetytests/test_build_merge_shrink_guard.py— full-run-safetytests/test_builtin_global_type_refs.py— full-run-safetytests/test_cache.py— full-run-safetytests/test_callflow_html.py— full-run-safetytests/test_cargo_introspect.py— full-run-safetytests/test_carried_hyperedge_remap.py— full-run-safetytests/test_case_sensitive_resolution.py— full-run-safetytests/test_charmap_encoding.py— impact, full-run-safetytests/test_chunking.py— impact, full-run-safetytests/test_cjs_module_extension.py— impact, full-run-safetytests/test_claude_cli_backend.py— impact, full-run-safetytests/test_claude_md.py— full-run-safetytests/test_cli_broken_pipe.py— full-run-safetytests/test_cli_export.py— full-run-safetytests/test_cli_help.py— full-run-safetytests/test_cluster.py— full-run-safetytests/test_codebuddy.py— full-run-safetytests/test_community_hub_labels.py— full-run-safetytests/test_community_labels_skill.py— full-run-safetytests/test_confidence.py— full-run-safetytests/test_corrupt_graph_json.py— full-run-safetytests/test_cpp_nested_and_cli.py— impact, full-run-safetytests/test_cpp_objc_cross_file_calls.py— full-run-safetytests/test_cpp_preprocess.py— full-run-safetytests/test_cross_extension_reexport_self_cycle.py— full-run-safetytests/test_cross_language_call_resolution.py— full-run-safetytests/test_cross_repo_member_calls.py— full-run-safetytests/test_cross_repo_shared_types.py— full-run-safetytests/test_csharp_call_site_generic_args.py— full-run-safetytests/test_csharp_enum_members.py— full-run-safety- … and 225 more
non-code file(s) changed (
CHANGELOG.md) → running the full suite for safety (a code graph can't see config/fixture/data deps)
changed code file(s) with no mapped test (
CHANGELOG.md) — a coverage gap or a missing link — running the full suite rather than only the selected tests
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
Could not verify: Could not verify detect.
The verifier did not have enough to check detect, 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: parameter `root` is annotated `Path` — outside the synthesizable primitive/collection set
· 52 more finding(s) on lines outside this diff (see the check run).
Fixes #2834
Summary
detect()kept appending nested.gitignoreand.graphifyignorerules whileos.walkmoved through the repository. Anchor checks preserved correctness, but every later directory/file check still scanned rules from completed sibling subtrees. On a monorepo with many independent projects, the matcher cost therefore grew with tree breadth rather than the active directory depth.Fix
graphifyignore_patternsfor existing diagnostics.Regression coverage
Added a deterministic test with 12 sibling projects and nested ignore files. It verifies that:
A simpler 12-sibling probe reaches 13 active rules on pristine
v8and only 2 on this branch, demonstrating the old unbounded accumulation directly.Measurements
Synthetic sibling-project corpus, 10 ignore rules per project, Windows local run:
The detected file count and loaded-rule count were identical in each run.
Validation
python -m pytest tests\\test_detect.py -q: 262 passed, 1 skippedpython -m pytest tests\\test_detect.py tests\\test_watch.py tests\\test_cache.py tests\\test_file_slice.py -q: 503 passed, 10 skipped; 2 pre-existing Windows failures in deleted-CWD watch testspython -m pytest tests\\ -q: 5,217 passed, 269 skipped, 38 pre-existing Windows/optional-environment failures; no changed detector-test failuresruff check graphify\\detect.py tests\\test_detect.pypython -m compileall -q graphifygit diff --checkNo new dependencies, subprocesses, network calls, or output formats were introduced.