Skip to content

TSExternalSymbol has multiple versions #231

Closed

Description

@georgesafta

Describe the bug
TSExternalSymbol model out of sync

It's defined as:

class TSExternalSymbol(_Base):
    """A WALA-style phantom node: a synthetic stub for a call target OUTSIDE the project (an
    imported/required library member). An edge's ``target`` byte-matches either a real
    ``TSCallable.signature`` or a ``TSExternalSymbol.signature``, so the call graph stays
    dangling-free while still recording external (e.g. sink) calls.

    Slim: the map key in ``TSApplication.external_symbols`` IS the signature (e.g.
    ``commander.parse``), and membership already means external — so neither is repeated here."""

    name: str
    module: str

while from Neo4J it is constructed as:

def external(props: Props) -> TSExternalSymbol:
    return TSExternalSymbol(
        signature=props.get("signature", ""),
        name=props.get("name", ""),
        module=props.get("module", ""),
        kind=props.get("kind", "unknown"),
    )

A similar behavior is present in the codeanalyzer:

To Reproduce
Load TS model from an application with external symbols.

Expected behavior
Single model

Logs
No

Additional context
No

Activity

  1. rahlk commented on Jul 14, 2026

    @rahlk
    Collaborator

    Retired by construction 2026-07-09: under schema v2, externals re-materialize as stub nodes (documented shift 5 of the schema contract) — the dual-shape TSExternalSymbol disappears with the old model layer. Lands via #241 (epic #238).

  2. rahlk commented on Jul 14, 2026

    @rahlk
    Collaborator

    Reopening — the earlier close ('retired by construction in F3/#241') was wrong for the 1.x line: F3 is 2.x work that doesn't exist yet, and this bug is live in every 1.4.x release. Verified on main today: reconstruct.external() (reconstruct.py:175-181) passes signature and kind to TSExternalSymbol, whose extra='forbid' model declares only name+module -> ValidationError('extra_forbidden') on ANY External node, even signature=''. Sole caller is TSNeo4jBackend.get_external_symbols (neo4j_backend.py:265), so that method is broken for every app with phantom nodes (the default). Constructor audit shows no sibling reconstructors share the mismatch. 1.x fix: the reconstructor conforms to the slim model (name+module only — the map key IS the signature, per the model's own docstring). Rides 1.4.3. The 2.x/F3 supersession still stands for the model layer itself.

  3. reopened this on Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions