code-review-graph version
2.3.8
Operating system
macOS
Python version
3.12.4
AI platform
claude-code
Output of code-review-graph status
INHERITS edges store the base type as raw source text. When the base is generic, the target is Base<Arg>, which never matches the class node Base, so the relationship is invisible. Worse than the omission: inheritors_of returns 0 with the confidence string "is indexed and no such edge is recorded" — an affirmative claim of absence, when the edge is present in the edges table and merely unresolved.
Steps to reproduce
mkdir -p /tmp/crg-generic && cd /tmp/crg-generic && git init -q .
cat > Bases.cs <<'EOF'
namespace App;
public abstract class PlainBase { }
public abstract class GenericBase { }
public class FromPlain : PlainBase { }
public class FromGeneric : GenericBase { }
EOF
code-review-graph build
code-review-graph query inheritors_of PlainBase
code-review-graph query inheritors_of GenericBase
Expected vs actual behavior
Actual
inheritors_of PlainBase → count=1 ['FromPlain'] confidence=None
inheritors_of GenericBase → count=0 []
confidence: "'…::GenericBase' is indexed and no such edge is recorded; graph currency unverified"
INHERITS Bases.cs::FromGeneric -> GenericBase
The target is the raw text GenericBase, which never matches node Bases.cs::GenericBase.
Expected
inheritors_of GenericBase returns FromGeneric. Failing that, a caveat that does not assert absence — no LanguageGap in uncertainty.py covers inheritors_of for C#, so this false negative is delivered unqualified.
For Java
package app;
abstract class PlainBase { }
abstract class GenericBase { }
class FromPlain extends PlainBase { }
class FromGeneric extends GenericBase { }
inheritors_of PlainBase = 1, inheritors_of GenericBase = 0.
Additional context
eShop project routes ordering commands through IdentifiedCommandHandler<T, R>. Every concrete handler inherits from a closed generic
public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CreateOrderCommand, bool> { }
So every one of them is invisible to inheritors_of, and CRG states positively that the base class has no inheritors. Since these handlers also declare no Handle of their own — it's inherited from the abstract base — there is no other edge connecting a concrete handler to its behavior.
Suggested fix
Resolve INHERITS targets by stripping type arguments before node matching, retaining the full constructed type in extra so the argument list is not lost (it is needed for any later type-substitution work). At minimum, stop emitting "no such edge is recorded" when an unresolved edge of that kind exists from the target.
code-review-graph version
2.3.8
Operating system
macOS
Python version
3.12.4
AI platform
claude-code
Output of
code-review-graph statusSteps to reproduce
mkdir -p /tmp/crg-generic && cd /tmp/crg-generic && git init -q .
cat > Bases.cs <<'EOF'
namespace App;
public abstract class PlainBase { }
public abstract class GenericBase { }
public class FromPlain : PlainBase { }
public class FromGeneric : GenericBase { }
EOF
code-review-graph build
code-review-graph query inheritors_of PlainBase
code-review-graph query inheritors_of GenericBase
Expected vs actual behavior
Actual
inheritors_of PlainBase → count=1 ['FromPlain'] confidence=None
inheritors_of GenericBase → count=0 []
confidence: "'…::GenericBase' is indexed and no such edge is recorded; graph currency unverified"
INHERITS Bases.cs::FromGeneric -> GenericBase
The target is the raw text GenericBase, which never matches node Bases.cs::GenericBase.
Expected
inheritors_of GenericBase returns FromGeneric. Failing that, a caveat that does not assert absence — no LanguageGap in uncertainty.py covers inheritors_of for C#, so this false negative is delivered unqualified.
For Java
package app;
abstract class PlainBase { }
abstract class GenericBase { }
class FromPlain extends PlainBase { }
class FromGeneric extends GenericBase { }
inheritors_of PlainBase = 1, inheritors_of GenericBase = 0.
Additional context
eShop project routes ordering commands through IdentifiedCommandHandler<T, R>. Every concrete handler inherits from a closed generic
public class CreateOrderIdentifiedCommandHandler : IdentifiedCommandHandler<CreateOrderCommand, bool> { }
So every one of them is invisible to inheritors_of, and CRG states positively that the base class has no inheritors. Since these handlers also declare no Handle of their own — it's inherited from the abstract base — there is no other edge connecting a concrete handler to its behavior.
Suggested fix
Resolve INHERITS targets by stripping type arguments before node matching, retaining the full constructed type in extra so the argument list is not lost (it is needed for any later type-substitution work). At minimum, stop emitting "no such edge is recorded" when an unresolved edge of that kind exists from the target.