Skip to content

Ruby: include/extend/prepend emit no mixin edges — Rails concern composition invisible (traversal already supports mixes_in) #1668

Description

@krishnateja7

Follow-up in the Ruby-coverage series (#1634, #1640 — both verified working on 0.9.6, thank you; also see #1666/#1667 for two smaller 0.9.6 regressions). This one is an enhancement request, and it is the largest Rails-shaped static gap we can still measure.

Symptom

include / extend / prepend produce no edges at all for Ruby. Measured on our graph (11,819 nodes, 5,631 Ruby nodes, 8,694 Ruby→Ruby links):

# links with relation in [mixes_in, uses, implements, extends] whose source is a .rb node
=> 0

Concrete repo-local example (both sides have nodes, so this is purely an extraction gap):

# app/models/roster_snapshot.rb
class RosterSnapshot < ApplicationRecord
  include SealedEntriesProtection   # app/models/concerns/sealed_entries_protection.rb

No edge exists between RosterSnapshot and SealedEntriesProtection in either direction. Same for every other concern include and for gem mixins (include AASM, Devise strategy modules, etc.).

Why this matters for Rails specifically

Concerns/mixins are the composition mechanism in Rails — validations, callbacks, scopes, and methods arrive via include, the way functionality arrives via explicit import in TypeScript. Today affected <Concern> returns nothing, so the blast radius of editing a shared concern (often the highest-risk edit in a Rails app) is invisible. The TS side of the same graph gets imports/implements/mixes_in-class treatment, which is a big part of why frontend recall is strong and Ruby recall lags.

Two things that make this cheap now

  1. Ruby: no nodes extracted for plain modules or Struct.new/Class.new constant assignments — their call edges are impossible even with resolution fixed #1640 made the targets exist. Plain modules now get real nodes, so include SomeConcern has a resolvable target node — before 0.9.6 this request would have been blocked on missing nodes.
  2. Traversal is already ready. affected already lists mixes_in in its traversed relations (Relations: calls, indirect_call, references, imports, imports_from, re_exports, inherits, extends, implements, uses, mixes_in, embeds) — only the Ruby extraction side is missing. Emitting ClassNode --mixes_in--> ModuleNode for include/extend/prepend with a constant argument would light it up end to end.

Resolution of the constant argument can presumably reuse the #1634 receiver-resolution machinery (same candidate laddering, same ambiguity handling).

Environment

graphifyy 0.9.6 (uv tool), macOS, Rails repo as in #1666.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions