Skip to content

feat(extract): Go native chan and goroutines are not modelled — the Go channel extractor only recognises WebSocket connections #1930

Description

@ilyabrykau-orca

feat(extract): Go's native chan and goroutines are not modelled — the Go channel extractor only recognises WebSocket connections

Status: draft implementation-proposal open — PR #1949 (v1: send/receive/select by grammar → gochan Channel nodes + EMITS/LISTENS_ON, package-qualified identity; element types, go statements and range-receives deferred as stated below); marked ready on maintainer design ack.

What is missing

Channel is an existing label with an existing per-language extractor (internal/cbm/extract_channels.c). The Go branch (extract_channels_gogo_process_call) only classifies gorilla/nhooyr-style WebSocket send/receive (WriteMessage/ReadJSON/… on receivers named conn/ws/c/…), emitting transport:"websocket" nodes named after the enclosing function. Go's own primitives — make(chan T), ch <- v, <-ch, select, close(ch), go f() — are untouched by any pass.

Damage measured (~1150-file Go repo)

construct source graph
make(chan …) 250 0
sends x <- v ~210 0
receives <-x ~500 0
go statements 245 0
Channel nodes 2 (both websocket)

The repository's event pipeline is channel-plumbed end to end (sources own an output channel; enrichment stages consume and re-emit; a consumer drains into storage). That producer/consumer topology — the most load-bearing structure in the codebase — is absent: trace_path stops at the send site and resumes nowhere.

Detection recipe

SELECT json_extract(properties,'$.transport'), count(*) FROM nodes WHERE label='Channel' GROUP BY 1;

vs grep -rho 'make(chan' --include='*.go' . | wc -l and grep -rhoE '^\s*go [a-zA-Z_(]' --include='*.go' . | wc -l.

Natural extraction points (scope, not a design)

  • Identity: a Go channel's stable identity is its declaration site — struct field (OutputChannel chan Event, strongest: shared across files by type) > package var > escaping local. Record the element type (the join key that makes producer/consumer pairs meaningful).
  • ch <- vEMITS (edge type exists; count 1 in this repo); <-ch / for range chLISTENS_ON (exists; count 2); select cases → same two, one per comm clause.
  • go f(...) → the existing CROSS_ASYNC notion; even without it, EMITS/LISTENS_ON pairs alone reconstruct the pipeline. close(ch) optional.
  • Transport "gochan", distinct from "websocket" so the existing classifier is untouched. The tree-sitter Go grammar already exposes everything (channel_type, send_statement, select_statement, go_statement); work confined to extract_channels.c + the pass that materialises Channel nodes.

Related: #1114 (edges that model indirection); tracked in #1932.

Metadata

Metadata

Assignees

No one assigned

    Labels

    parsing/qualityGraph extraction bugs, false positives, missing edges

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions