Skip to content

fix(n8n): seed reachability from independent main-subgraph heads (closes #57)#58

Open
hatyibei wants to merge 1 commit into
mainfrom
fix/n8n-independent-main-subgraph
Open

fix(n8n): seed reachability from independent main-subgraph heads (closes #57)#58
hatyibei wants to merge 1 commit into
mainfrom
fix/n8n-independent-main-subgraph

Conversation

@hatyibei

Copy link
Copy Markdown
Owner

Closes #57.

Fourth and final unreachable_node FP pattern from the n8n dogfood loop: nodes on the main data-flow flagged unreachable because they head an independent subgraph the trigger can't reach.

Root cause

n8n bundles several independent flows in one document — a triggered main flow alongside manually-run fragments or sub-workflow bodies the author starts from an arbitrary node. Reachability was seeded only from trigger nodes, so every node of a non-triggered fragment was reported unreachable.

Representative case — Autonomous AI crawler.json (38 nodes, 0 disabled): the crawler subgraph is rooted at Set domain (URL) / Set domain (text), which have no incoming main edge. From there 16 nodes (Get website, Aggregate URLs, Convert HTML to Markdown, …) cascaded to unreachable.

Fix

Seed reachability from triggers PLUS the head of every independent main subgraph — a node with no incoming main edge but ≥1 outgoing main edge (entryRootIDs, replacing allTriggerNodeIDs).

  • Fully-detached nodes (no in, no out) are not roots → genuine dead nodes still surface as unreachable_node. Detection power preserved.
  • ai_* edges are excluded: the reachability rule already treats them as undirected, and a sub-resource (model/memory/tool) has only ai_* edges, so it never becomes a spurious root.

Impact (308 real workflows)

stage unreachable_node
pre-fixes (v0.9.1) 973
after #56 (3 fixes) 198
this fix 32 (−166)

Across all four n8n fixes: 973 → 32 (−96.7%). Autonomous AI crawler: 16 → 0.

Residual 32 = 6 minor FPs (noOp/agent, separate small pattern) + 26 genuinely-detached dead nodes (true positives — nodes placed but never wired). The FP tail is essentially gone; what remains is mostly correct.

Tests

  • TestN8nParser_IndependentMainSubgraphRoot: an independent subgraph head is wired from the virtual root; a fully-detached node is not.
  • go test ./domain/rules/... ./infrastructure/parser/... green.

🤖 Generated with Claude Code

n8n documents routinely bundle several independent flows in one file: a
triggered main flow alongside manually-run fragments or sub-workflow bodies
the author starts from an arbitrary node. Reachability was seeded only from
trigger nodes, so every node of a non-triggered fragment was reported as
unreachable_node — 125 of the 198 residual FPs after the earlier n8n fixes,
e.g. the entire 38-node "Autonomous AI crawler" subgraph rooted at the
incoming-edge-less "Set domain (URL)" (16 nodes, all FP).

Fix: seed reachability from triggers PLUS the head of every independent main
subgraph — a node with no incoming `main` edge but >=1 outgoing `main` edge
(new entryRootIDs, replacing allTriggerNodeIDs). Fully-detached nodes (no in,
no out) are NOT roots, so genuine dead nodes still surface as unreachable_node.
ai_* edges are excluded: the rule already treats them as undirected, and a
sub-resource (model/memory/tool) has only ai_* edges so it never becomes a
spurious root.

Measured on 308 real workflows (enescingoz/awesome-n8n-templates),
unreachable_node: 198 -> 32 (this fix -166); across all four n8n fixes
973 -> 32 (-96.7%). Residual 32 = 6 minor FPs + 26 genuinely-detached dead
nodes (true positives). "Autonomous AI crawler": 16 -> 0.

Test: IndependentMainSubgraphRoot (an independent subgraph head is a
virtual-root child; a fully-detached node is not). go test ./domain/rules/...
./infrastructure/parser/... green. Closes #57.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

n8n: main-flow subgraph reported as unreachable_node (residual FP after #56)

1 participant