Skip to content

fix(merge): resolve cross-batch edge endpoints with mismatched node-type prefix - #624

Open
edunovaes wants to merge 1 commit into
Egonex-AI:mainfrom
edunovaes:fix/cross-batch-prefix-resolution
Open

edunovaes wants to merge 1 commit into
Egonex-AI:mainfrom
edunovaes:fix/cross-batch-prefix-resolution

Conversation

@edunovaes

@edunovaes edunovaes commented Aug 6, 2026

Copy link
Copy Markdown

Fixes #628

Problem

merge-batch-graphs.py silently drops cross-batch edges whose endpoint carries the wrong node-type prefix.

Each file-analyzer subagent picks the ID prefix for a node it owns (file: / config: / document: / pipeline: / table: / schema: / endpoint:). When batch A emits an edge pointing at a file that batch B classified, A has to guess that prefix — batchImportData and neighborMap only resolve project-internal code imports, so doc→pipeline, doc→config and config→code references have no ground truth.

Step 6 then compares IDs by exact equality and drops anything that doesn't match:

if src not in node_ids or tgt not in node_ids:
    unfixable.append(f"Edge {src}{tgt} ({etype}): dropped, missing ...")
    continue

Code files almost always end up as file:, so the loss lands entirely on the non-code node types — which is where the most valuable semantic edges live (documents, triggers, configures, depends_on).

The failure is quiet: the drop only reaches stderr, and the only consumer of that stderr in the pipeline is the optional Phase 3 assemble-reviewer LLM agent. Runs that skip it (or that don't read its output closely) lose the edges with no visible signal — the final graph just has fewer relationships than it should.

Real-world impact

On a 205-file project (Next.js CRM + 46 SQL migrations + 17 n8n workflow docs + docs tree), a single /understand run had 25 edges about to be dropped this way. 21 of them were documents edges from README.md / CLAUDE.md / two other root docs → pipeline:n8n-workflows/*.md — the batch that owned the docs guessed document:, the batch that owned the workflow files chose pipeline:. That is the entire "which document describes which automation" map, gone.

The remaining 4 were file: vs config: (next.config.ts, a large JSON data file). Exactly one of the 26 reported drops was legitimate (a path referenced in a doc that no longer exists on disk).

Fix

Before dropping, try to resolve the endpoint ignoring its prefix.

  • Consulted only for IDs already headed for the drop — edges that resolve today take an unchanged path.
  • Remaps only when exactly one node shares the ID body. If both file:x.ts and config:x.ts exist, the ID stays ambiguous and the edge is dropped and reported exactly as it is today.
  • Therefore it cannot corrupt an edge that currently works; the worst case is the existing behaviour.

The count surfaces in the existing "Fixed" report section:

Fixed (25 corrections):
    25 × edge endpoints resolved to correct node-type prefix

Tests

Adds PrefixResolutionTests to tests/skill/understand/test_merge_batch_graphs.py — six cases through merge_and_normalize, covering both the recovery and the guardrails:

Edge target Graph contains Expected
document:wf/a.md pipeline:wf/a.md resolved
config:src/x.ts file:src/x.ts resolved
document:ghost/nope.md still dropped
document:amb/y.ts file:amb/y.ts and config:amb/y.ts still dropped (ambiguous)
two resolvable edges reported under "Fixed"
pipeline:wf/a.md (already valid) pipeline:wf/a.md untouched
$ python -m unittest tests.skill.understand.test_merge_batch_graphs
Ran 86 tests in 0.61s
OK

$ python -m unittest tests.skill.understand.test_merge_subdomain_graphs
Ran 6 tests in 0.00s
OK

The diff is additive only (+130 / −0); no existing test changed.

Also run against the real 205-file project described above: 511 nodes, 1011 edges, 25 endpoints resolved, 1 legitimate drop remaining, and the resulting graph passes the Phase 6 inline validator with 0 issues.

Notes

  • No new dependencies, no signature changes, no behavioural change for graphs that currently merge cleanly.
  • VALID_NODE_PREFIXES is reused for the prefix test rather than hardcoding a second list, so new node types are picked up automatically.
  • An alternative fix would be to have compute-batches.mjs publish an authoritative path → nodeType map to every batch, so analyzers never have to guess. That's a bigger change; this one is the safety net regardless of whether that lands.

This branch has not been deployed

No deployments
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.

Cross-batch edges are silently dropped when the node-type prefix differs

1 participant