Emit a bare file node for skipped data JSON (#2108) - #3626
ayushcodes10 wants to merge 3 commits into
Conversation
extract_json already built the file node before checking whether the document was a recognized config or manifest, but the skip branches threw that node away and returned an empty node list, so a data shaped JSON file such as an eval fixture or a parity corpus never appeared anywhere in the graph at all, not even as a leaf. Both skip paths now return the already built nodes list, which at that point holds exactly the one bare file node and nothing else: no per key traversal, no children, no edges. The file becomes discoverable through query, explain, and affected without reintroducing the orphan key node explosion the original skip was added to prevent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Updates the two existing tests that pinned an empty node list for skipped data JSON to assert the new bare file node instead, and adds two more: the node looks like a normal file node (same id scheme, file_type code, no error key), and a small corpus of data files still gets exactly one node per file, never per key nodes. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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
Emits the bare file node for data-shaped .json files that fail the config/manifest check in extract_json, instead of returning an empty node list, so eval fixtures, datasets, and array/scalar-rooted JSON stay discoverable via query/explain/affected. The skip path still emits no per-key nodes and no edges, preserving the #1224 orphan-key-explosion fix — one file node per file regardless of corpus size. The file node carries the standard id scheme, file_type "code", and no error key, matching every other file node graphify emits.
No blocking issues surfaced.
Analysis details — impact, health, verification
Impact & health
Graphify review
Impact — 637 functions depend on the 637 functions this change touches.
Health — this change adds coupling hotspots:
- new:
extract_json()— 18 callers, 7 callees - new:
walk_object()— 1 callers, 7 callees
Verification — 637 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: 637 function(s) in the blast radius were not formally verified this run
Test selection
Test selection
286 of 286 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— 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— 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— 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— full-run-safetytests/test_chunking.py— full-run-safetytests/test_cjs_module_extension.py— full-run-safetytests/test_claude_cli_backend.py— 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— 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_external_call_guards.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-safety- … and 236 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 extract\_json.
The verifier did not have enough to check extract\_json, 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: parameter `path` is annotated `Path` — outside the synthesizable primitive/collection set
· 2 more finding(s) on lines outside this diff (see the check run).
Summary
Fixes #2108. Data-shaped
.json(eval fixtures, parity corpora, i18n catalogues, GeoJSON) is deliberately skipped byextract_json's AST pass — the right call for structure, since walking it exploded into hundreds of orphan key-nodes (#1224). But the skip was total: the file contributed no node at all, so it was entirely absent fromgraph.jsonand unreachable fromquery/explain/affected, with no warning that anything was missing.Root cause
extract_jsonalready builds the file node (file_nid = _make_id(str(path)); add_node(file_nid, path.name, 1)) before deciding whether the document is a recognized config/manifest. Both skip branches then discarded it, returning a literal{"nodes": [], ...}instead of thenodeslist — which at that point held exactly that one file node and nothing else.Fix
Both skip paths (non-config object root, and non-object top-level root) now return the already-built
nodeslist instead of an empty one. Since nothing else has been added to it by that point, this yields exactly one bare file node — no per-key traversal, no children, no edges — keeping the file discoverable without reintroducing the node explosion #1224 fixed. Verified the size-limit and invalid-JSON early-return paths are unaffected (they return before the file node is ever built).Test plan
test_extract_json_data_file_skippedandtest_extract_json_top_level_array_skippedintests/test_extract.py, which previously pinned an empty node list, to assert the new single bare-file-node behavior.test_extract_json_data_file_node_is_a_real_file_node(same id scheme,file_type: "code"matching.json'sCODE_EXTENSIONSclassification, noerrorkey) andtest_extract_json_many_data_files_still_one_node_each(a small corpus of data files stays AST pass explodes data .json into orphan key-nodes (CODE_EXTENSIONS includes .json) — 561 isolated nodes on a real repo #1224-safe: exactly one node per file, never per-key nodes).tsconfig.json,package.json-shaped fixtures) is unaffected — full structural extraction still runs.python3 -m pytest -q— 5623 passed, 68 skipped, no regressions.🤖 Generated with Claude Code