Skip to content

Python multiple-inheritance assemblies do not model sibling-base methods satisfying abstract mixins #1283

Description

@Enferlain

Version

codebase-memory-mcp dev

Platform

Linux (x64)

What happened?

A Python class assembled from sibling bases can satisfy an abstract mixin method through C3/MRO lookup, but the graph has no relationship representing the effective method owner within the assembled class.

This is different from an ordinary override. The concrete method's declaring class does not inherit the abstract mixin and should not receive a globally valid OVERRIDE edge. The relationship exists only in the final multiple-inheritance assembly.

Minimal shape

from abc import ABC, abstractmethod

class Capability(ABC):
    @abstractmethod
    def process(self) -> str:
        raise NotImplementedError

class ProcessFacet:
    def process(self) -> str:
        return "processed"

class FinalStrategy(ProcessFacet, Capability):
    pass

At runtime, FinalStrategy is concrete and FinalStrategy().process() resolves to ProcessFacet.process. However, ProcessFacet.process is not an override of Capability.process outside this assembly.

The graph needs an assembly-scoped representation such as:

within FinalStrategy:
    Capability.process is satisfied/resolved by ProcessFacet.process

rather than an unconditional:

ProcessFacet.process -OVERRIDE-> Capability.process

Public production reproduction

Repository and commit:

The relevant assembly is:

class SdTrainingStrategy(
    SdModelLoadingStrategy,
    SdTokenizeStrategy,
    SdTextEncodingStrategy,
    # ...
    WeightedPromptStrategy,
    TrainingStrategy,
):
    ...

WeightedPromptStrategy declares two abstract methods:

tokenize_with_weights(...)
encode_tokens_with_weights(...)

They are supplied by different earlier sibling bases:

SdTokenizeStrategy.tokenize_with_weights
SdTextEncodingStrategy.encode_tokens_with_weights
SdxlTokenizeStrategy.tokenize_with_weights
SdxlTextEncodingStrategy.encode_tokens_with_weights

Graph evidence

A fresh full index reported:

12,131 nodes
70,850 edges
generation_matches=true

The class graph correctly stores:

  • all direct INHERITS edges;
  • the ordered base_classes arrays;
  • both diamond paths through the concrete facets and combined TrainingStrategy;
  • ordinary facet-to-contract OVERRIDE edges.

All six weighted-prompt method nodes exist, but none has an OVERRIDE relation:

MATCH (m:Method)
WHERE m.name IN ['tokenize_with_weights', 'encode_tokens_with_weights']
  AND m.qualified_name STARTS WITH 'home-imi-Projects-sd-scripts.library.strategies.'
OPTIONAL MATCH (m)-[:OVERRIDE]->(base:Method)
RETURN m.qualified_name, m.decorator_tags, base.qualified_name
ORDER BY m.qualified_name

Actual result:

WeightedPromptStrategy.encode_tokens_with_weights     abstractmethod  -
WeightedPromptStrategy.tokenize_with_weights          abstractmethod  -
SdTextEncodingStrategy.encode_tokens_with_weights     -               -
SdTokenizeStrategy.tokenize_with_weights              -               -
SdxlTextEncodingStrategy.encode_tokens_with_weights   -               -
SdxlTokenizeStrategy.tokenize_with_weights            -               -

A static C3/MRO audit found 62 abstract requirements satisfied across the three final strategy families. A graph traversal using INHERITS -> DEFINES_METHOD -> OVERRIDE could reconstruct 58. The missing four are exactly the sibling-base weighted-prompt implementations above.

All cited source paths returned no_recorded_issue with matching coverage metadata.

Expected behavior

The graph or resolver should model effective inherited method ownership for an assembled Python class while respecting:

  • declared base order;
  • C3 linearization;
  • diamonds;
  • abstract methods satisfied by an earlier sibling base;
  • same-named methods on unrelated bases.

Possible representations include an assembly-scoped method-resolution edge or deriving the effective owner from the stored ordered base_classes information. A global OVERRIDE edge between otherwise unrelated sibling classes would be misleading.

Queries and call resolution for a receiver typed as FinalStrategy should be able to identify ProcessFacet.process as its effective method without claiming that every ProcessFacet implements Capability.

Impact

This affects mixin/facet architectures beyond this repository:

  • abstract-implementation completeness audits can report missing implementations;
  • method ownership for final assembled classes is unavailable;
  • receiver resolution may fall back to unrelated same-name candidates;
  • call tracing and impact analysis cannot reliably connect calls through the final type to the MRO-selected facet method.

Related issues

Confirmations

  • Searched current open and closed issues; no exact duplicate found.
  • Public OSS reproduction.
  • Relevant files have current coverage metadata with no recorded parse gaps.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcypherCypher query language parser/executor bugsparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions