Skip to content

feat(extract): model Go native channels as gochan Channel topology - #1949

Draft
ilyabrykau-orca wants to merge 1 commit into
DeusData:mainfrom
ilyabrykau-orca:feat/go-native-channels
Draft

ilyabrykau-orca wants to merge 1 commit into
DeusData:mainfrom
ilyabrykau-orca:feat/go-native-channels

Conversation

@ilyabrykau-orca

@ilyabrykau-orca ilyabrykau-orca commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

Part of #1930draft implementation-proposal per the extraction points sketched in the issue body; will mark ready on a maintainer design ack.

What

Go's own concurrency primitives were invisible: the Go channel extractor only classified gorilla/nhooyr WebSocket send/receive, so a channel-plumbed event pipeline (250 make(chan …), ~710 send/receive sites on the measured repo) produced zero Channel nodes and trace_path stopped dead at every send site.

How (v1, extraction-only — the existing materializer does the rest)

create_channel_edges_for_file and its parallel twin already build Channel nodes + EMITS/LISTENS_ON edges from CBMChannel records, so the whole change lives in the Go extractor:

Also fixes a latent gap this exposed: enclosing_function_qn returned a bare name, which never matches any def QN — so every channel edge (the WebSocket ones included) silently degraded to the file node via find_channel_source's fallback. It now returns module_qn.name, fallback preserved.

Tests (reproduce-first — RED with extract_channels.c stashed)

  • extract_go_native_channels: EMIT+LISTEN records, package-qualified names, unary minus is not a receive.
  • pipeline_go_native_channel_topology: one gochan Channel node with "transport":"gochan", EMITS from Produce and LISTENS_ON from Drain across files (RED: cc == 0, expected 1).
  • 643 green across extraction/pipeline/registry; full scripts/test.sh venue leg green; clang-format clean.

Field census

Landed (same-day baseline, repo @ f555e5ce): Channel nodes 2 → 205 (203 gochan); EMITS 1 → 162; LISTENS_ON 2 → 256; 252 distinct source functions. The gap to the raw source counts is exactly the deferred shapes (non-escaping locals, for range ch, go statements). Full table in the census comment below.

#1932 tracks the family. Related: #1114.

@github-actions

Copy link
Copy Markdown

Thanks for opening this — it has been seen, and it is queued.

This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence.

Current review status: working through a backlog. 0.9.1-rc.1 is out, so the release freeze that held reviews is over — but it left a large queue of open pull requests behind it, and we are reading through them oldest-first. The background is in discussion #1144.

What that means for this PR, concretely:

  • It will not be closed for inactivity. No stale bot touches pull requests here.
  • It may still sit a while before a human reads it. That is on us, not on you.
  • Older PRs are read first, so a recent one is not being skipped — it is behind a queue.

Things that will genuinely speed it up whenever review does happen:

  • Keep it rebased on main — the tree is moving quickly right now, and a conflicting branch cannot be reviewed as the diff you intended.
  • Get CI green, or say which failures you believe are pre-existing.
  • Keep the change to one claim. Bundled features and refactors get split before they get merged, which costs you a round trip.
  • Every commit needs a sign-off (git commit -s) — CI enforces DCO.

If this fixes a bug, a reproduction we can run is worth more than a description of the symptom.

Thanks for contributing, and sorry in advance for the wait.

@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

CI retrigger (no-op amend): test-windows-guards — identical SETUP FAIL: ASCII baseline did not index … nodes: None harness-setup signature, tracked in #1952. No semantic changes.

@ilyabrykau-orca
ilyabrykau-orca force-pushed the feat/go-native-channels branch from f962097 to e41c7df Compare August 31, 2026 08:41
@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

Field census landed (same-day baseline vs this branch, repo @ f555e5ce):

main #1949
Channel nodes 2 (both websocket) 205 — 203 gochan + the same 2 websocket
EMITS 1 162
LISTENS_ON 2 256
distinct source functions on gochan edges 252

Against the issue's source counts (~210 sends, ~500 receives): 162 sends and 256 receives captured — the gap is exactly the deferred shapes (locals that never escape, for range ch, go-statement plumbing), per the v1 scope statement. The event pipeline's producer/consumer topology is now walkable.

@DeusData DeusData added enhancement New feature or request parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Sep 1, 2026
@DeusData

DeusData commented Sep 1, 2026

Copy link
Copy Markdown
Owner

Thank you for documenting the measured Go channel gap, the extraction-only boundary, and the positive and negative tests. Because this draft changes graph identity and cross-file channel topology, we need more time to review the design carefully. Please keep it in draft for now; the contribution queue is quite full, but we will come back with a grounded decision as soon as capacity allows.

Go's own concurrency primitives were invisible: the Go channel
extractor only classified gorilla/nhooyr WebSocket send/receive, so a
channel-plumbed event pipeline (250 make(chan ...), ~710 send/receive
sites on the measured repo) produced zero Channel nodes and trace_path
stopped dead at every send site.

v1, extraction-only - the existing per-file materializer
(create_channel_edges_for_file and its parallel twin) already builds
Channel nodes and EMITS/LISTENS_ON edges from CBMChannel records:

- send_statement (x <- v) -> EMIT, unary <- -> LISTEN. Both are channel
  operations BY GRAMMAR, so no type inference is needed for precision -
  unlike the WebSocket name heuristics. select comm clauses are covered
  for free (they contain the same node kinds).
- Channel identity: the package-qualified tail identifier
  (module_qn + '.' + field/var name), transport "gochan" - distinct
  from "websocket", whose classifier is untouched. Same-package
  cross-file producer/consumer pairs join on one node.
- Deliberately deferred (documented in DeusData#1930): element types on the
  node, go statements (CROSS_ASYNC), and for-range receives - range
  needs the operand's TYPE to know it is a channel, and a name-shape
  guess would be the DeusData#1932 anti-pattern.

Also fixes a latent gap this exposed: enclosing_function_qn returned a
BARE name, which never matches any def QN, so every channel edge (the
WebSocket ones included) silently degraded to the file node through
find_channel_source's fallback. It now returns module_qn.name, with
the file-node fallback preserved for shapes it cannot express.

Reproduce-first (RED with extract_channels.c stashed):
extract_go_native_channels (EMIT+LISTEN records, package-qualified
names, unary minus not mistaken for a receive) and
pipeline_go_native_channel_topology (one gochan Channel node,
EMITS from Produce and LISTENS_ON from Drain across files). 643 green
across extraction/pipeline/registry.

Part of DeusData#1930

Signed-off-by: Ilya Brykau <ilya.brykau@orca.security>
@ilyabrykau-orca

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (staying in draft as asked). Conflicts were test insertion-anchor drift in tests/test_extraction.c and tests/test_pipeline.c — re-anchored; all source auto-merged. Full scripts/test.sh green on this head.

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

enhancement New feature or request parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants