Skip to content

fix(watch): preserve semantic evidence across AST id collisions - #4950

Closed
andrebrait wants to merge 1 commit into
Graphify-Labs:v8from
pfBlockerNG:fix/semantic-ast-collision
Closed

andrebrait wants to merge 1 commit into
Graphify-Labs:v8from
pfBlockerNG:fix/semantic-ast-collision

Conversation

@andrebrait

@andrebrait andrebrait commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

Problem

An AST-only update silently discards saved cross-file semantic evidence when a freshly extracted AST node takes its id. Reproduced while auditing tracked semantic graphs, including a CodeRabbit concept in Leveret.

Change

  • Retain sourced semantic evidence during AST reconciliation and namespace cross-file collisions through the existing reference alias helper.
  • Scope preservation to AST updates; full-build deduplication keeps its existing definer rules, and fresh AST facts remain authoritative for same-source ids.
  • Preserve authored AST links, semantic links, hyperedges, confidence, and opaque document-version attributes.
  • Allocate a free alias when the usual citing-file namespace is occupied. Cover clustered and --no-cluster updates.

Only graph.json carries portable provenance. No extraction cache is tracked, and no cache-based freshness requirement or commit/push hook policy is introduced.

Verification

Full upstream CI was not run on the fork because its Actions are disabled. No upstream bot review requests were posted because the authenticated account has read-only permission in the base repository.

@github-actions

github-actions Bot commented Nov 2, 2026

Copy link
Copy Markdown

Thanks for the pull request, @andrebrait. 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.

@github-actions github-actions Bot added the contributor Pull request from a returning community contributor label Nov 2, 2026
andrebrait added a commit to pfBlockerNG/graphify that referenced this pull request Nov 2, 2026
…AST id collisions

Squashed from origin/fix/semantic-ast-collision (db62842) onto upstream/v8.
@andrebrait
andrebrait force-pushed the fix/semantic-ast-collision branch from db62842 to 6e0de8f Compare November 2, 2026 12:58
andrebrait added a commit to pfBlockerNG/graphify that referenced this pull request Nov 2, 2026
…AST id collisions

Squashed from origin/fix/semantic-ast-collision (6e0de8f) onto upstream/v8.

@graphify-labs graphify-labs Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View in Graphify

Graphify reviewed this change.

Worth a look — the grounded gate found no coupling regressions or blocking issues, but 1 advisory finding(s) below merit a look before merge.

Not checked: tests were not run; no formal proof of the changed code.


Graphify review — findings

Fixes AST-only watch updates dropping semantic evidence whose node id collides with a code definition: _reconcile_existing_graph now keeps saved semantic nodes that have a source_file, then runs them through _namespace_reference_stub_collisions so both the code definition and the document-owned node survive in graph.json, with or without --no-cluster. The collision pass gains a preserve_saved_semantics mode that namespaces pre-marker semantic nodes from other files, falls back to numbered suffixes when the __ref__ name is already taken, and leaves AST-origin edges alone. Afterward, any leftover non-AST node sharing an id with a fresh AST node (same-source, external-stub or sourceless copies) is discarded so it can't overwrite the new definition, which also drops its provenance if it wasn't renamed.

Worth a look

  • Semantic copies left unrenamed are silently dropped along with their provenance — graphify/watch.py:1358 · Escalate · medium
    • NOT verified (no proof, no reproducing execution) — needs human review
Analysis details — impact, health, verification

Impact & health

Graphify review

Impact — 1288 functions depend on the 463 functions this change touches.

Health — this change adds coupling hotspots:

  • worse: _rebuild_code() — 218 callers, 67 callees
  • worse: _reconcile_existing_graph() — 1 callers, 14 callees

Verification — 1288 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: 1024 function(s) in the blast radius were not formally verified this run

Test selection

Test selection

489 of 489 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/pi.test.ts — full-run-safety
  • tests/test_4874_jvm_resolution.py — full-run-safety
  • tests/test_4909_reference_binding_scale.py — full-run-safety
  • tests/test_affected_cli.py — full-run-safety
  • tests/test_affected_defines.py — full-run-safety
  • tests/test_affected_member_seed.py — full-run-safety
  • tests/test_affected_overrides.py — full-run-safety
  • tests/test_affected_path_file_node.py — full-run-safety
  • tests/test_affected_seed_reference_forms.py — full-run-safety
  • tests/test_agents_platform.py — full-run-safety
  • tests/test_alias_folding.py — full-run-safety
  • tests/test_analyze.py — full-run-safety
  • tests/test_anthropic_custom_endpoint.py — full-run-safety
  • tests/test_antigravity_install.py — full-run-safety
  • tests/test_apm_fallback_version.py — full-run-safety
  • tests/test_architecture_doc.py — full-run-safety
  • tests/test_astro_extraction.py — full-run-safety
  • tests/test_astro_import_ids.py — full-run-safety
  • tests/test_atomic_canvas_export.py — full-run-safety
  • tests/test_atomic_version_stamp.py — full-run-safety
  • tests/test_atomic_writes.py — full-run-safety
  • tests/test_backend_env_isolation.py — full-run-safety
  • tests/test_backend_extras.py — full-run-safety
  • tests/test_backend_opt_in.py — full-run-safety
  • tests/test_benchmark.py — full-run-safety
  • tests/test_benchmark_raw_graph.py — full-run-safety
  • tests/test_benchmark_real_query.py — full-run-safety
  • tests/test_binary_media_words.py — full-run-safety
  • tests/test_blade_extractor.py — full-run-safety
  • tests/test_build.py — impact, full-run-safety
  • tests/test_build_located_semantic_identity.py — impact, full-run-safety
  • tests/test_build_merge_dedup_scope.py — impact, full-run-safety
  • tests/test_build_merge_hyperedges_and_prune.py — impact, full-run-safety
  • tests/test_build_merge_shrink_guard.py — impact, full-run-safety
  • tests/test_builtin_global_type_refs.py — full-run-safety
  • tests/test_c_include_resolution.py — impact, full-run-safety
  • tests/test_cache.py — full-run-safety
  • tests/test_cache_long_paths.py — full-run-safety
  • tests/test_cache_stale_import_target.py — impact, full-run-safety
  • tests/test_callflow_html.py — full-run-safety
  • tests/test_cargo_introspect.py — full-run-safety
  • tests/test_cargo_missing_manifest.py — full-run-safety
  • tests/test_carried_hyperedge_remap.py — impact, full-run-safety
  • tests/test_case_only_decl_ids_4904.py — full-run-safety
  • tests/test_case_sensitive_resolution.py — full-run-safety
  • tests/test_charmap_encoding.py — full-run-safety
  • tests/test_chunking.py — impact, full-run-safety
  • tests/test_cjs_module_extension.py — full-run-safety
  • tests/test_claude_cli_backend.py — full-run-safety
  • tests/test_claude_md.py — full-run-safety
  • … and 439 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.

· 2 more finding(s) on lines outside this diff (see the check run).

@safishamsi

Copy link
Copy Markdown
Member

Landed in 0.9.101 (published to PyPI), cherry-picked with your authorship preserved. This is the AST-id-collision facet (a saved semantic node whose id collides with a fresh code definition in the reconcile path); it is distinct from the clustered build fold in #4896/#4927, and both shipped. Thanks @andrebrait.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor Pull request from a returning community contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants