Skip to content

TypeScript extraction emits internal edges whose endpoint nodes are absent #2143

Description

@kitsupanic

Environment

  • graphifyy 0.9.25
  • macOS
  • Expo / React Native TypeScript corpus
  • code-only, undirected, no clustering

Reproduction

graphify extract . --out /tmp/graphify-diagnostic --no-cluster --code-only --force
graphify diagnose multigraph \
  --graph /tmp/graphify-diagnostic/graphify-out/graph.json \
  --undirected --max-examples 20

After excluding 93 intentional external ref_* imports covered by #2130 and #2132, 21 missing endpoints remain. Every missing ID is internal to the scanned corpus.

Observed internal failures

Nested function callers are referenced but never emitted (8 edges)

One TSX component emits six calls edges whose source is a nested capture callback ID. No node with that ID exists, while the targets are valid emitted nodes. The callback calls functions for region/date ordering, preview cropping, crop variants, candidate extraction, vertical-region filtering, and translation.

The same pattern occurs for nested submit and changeDate functions in another TSX component.

Representative fixture shape:

import { target } from "./target";

export function Component() {
  const capture = async () => target();
  return null;
}

Test-file caller IDs use an absent absolute-path form (6 edges)

Six indirect_call edges use source IDs shaped like:

users_<redacted>_src_components_additemscreen_test_tsx

The actual emitted file node uses a root-relative ID shaped like:

src_components_additemscreen_test

Equivalent mismatches occur across four TSX component test files.

Imported internal constants/assets have no target node (7 edges)

Missing targets represent:

  • four exported scalar constants imported from TypeScript service modules
  • one imported JSON asset
  • two generated migration imports (a SQL module and migration journal JSON)

Representative fixture shapes:

// constants.ts
export const LIMIT = 14;

// consumer.ts
import { LIMIT } from "./constants";
import data from "./data.json";

Expected behavior

Every non-external edge endpoint should resolve to an emitted node. Depending on the construct, Graphify could:

  1. emit a node for the nested function, constant, asset, or generated module;
  2. anchor the edge to the nearest emitted containing function or file node; or
  3. omit the edge rather than emit structurally invalid extraction data.

Absolute-path caller IDs should be normalized consistently against the extraction root.

Impact

build_from_json() drops all 21 edges, removing genuine internal call and import relationships. After #2132 classifies external imports separately, these remain as true dangling_endpoint_edges.

Suggested regression assertions

  • A nested TS/TSX callback calling an imported function has an emitted source endpoint.
  • Test-file indirect_call edges use the same root-relative file ID as the emitted file node.
  • Imported scalar constants and JSON/generated modules resolve to nodes or their containing file.
  • After excluding classified external imports, dangling_endpoint_edges == 0.

I can provide reduced real cache entries for these three patterns if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions