Skip to content

symfonic.devtools.archgate.reachability

reachability

RCH-1 — a capability or service package nothing imports is not shipped.

The gate this repository most needed and did not have.

The full-framework refactor completed all 72 of its ledger tasks and produced ~48,000 lines of new architecture that serves no request, because every task verified its own contracts and none asked "does anything call this?". The same defect appeared at four smaller scales in a single review session: an exported max_calls_per_invocation with no reader, a CapabilityConfig protocol with no implementation, a delete_subtree implemented on three backends with no caller, and 15 modules of effect fence with no importer.

A green suite cannot catch this. Every one of those had passing tests — tests written against the thing itself, which is exactly the blind spot. Reachability is a property of the graph, so it needs a check that reads the graph.

Scope, deliberately narrow:

  • Only symfonic.capabilities.* and symfonic.services.*. Those are internal wiring by construction — something in src/ is supposed to compose them.
  • Entry-point packages are exempt because "no importer in src" is their correct state: agent.fastapi is imported by an adopter's app, agent.cli and devtools.* by a console script, tools.mcp by adopter code. Judging them by this rule would train people to ignore it.
  • A package importing only its own submodules does not count as reached. That is what makes an orphan island of eleven packages an orphan island rather than eleven mutual endorsements.

The rule is not "delete this". It is "wire it, or say in the exception registry why it ships unreached, with an expiry". An unreachable package is either debt with a date or a deletion nobody has performed.

check_reachability

check_reachability(modules: dict[str, ModuleInfo]) -> list[Violation]

Gated packages that no module outside themselves imports.

Source code in src/symfonic/devtools/archgate/reachability.py
def check_reachability(modules: dict[str, ModuleInfo]) -> list[Violation]:
    """Gated packages that no module outside themselves imports."""
    gated: set[str] = set()
    for name in modules:
        package = _package_of(name)
        if package is not None:
            gated.add(package)

    reached: set[str] = set()
    for name, info in modules.items():
        importer_package = _package_of(name)
        for record in info.imports:
            target = _package_of(record.target)
            if target is None or target == importer_package:
                # Self-imports do not reach: a package cannot vouch for itself.
                continue
            reached.add(target)

    violations: list[Violation] = []
    for package in sorted(gated - reached):
        loc = sum(
            info.line_count
            for name, info in modules.items()
            if name == package or name.startswith(package + ".")
        )
        violations.append(
            Violation(
                rule="RCH-1",
                message=(
                    f"{package} ({loc} lines) is imported by nothing outside itself. "
                    "A capability or service package is internal wiring: if no "
                    "composition root reaches it, it ships as code that cannot run, "
                    "and its tests prove only that it is self-consistent. Wire it "
                    "from the composition root, or register an exception with an "
                    "expiry naming the task that will."
                ),
                modules=(package,),
            )
        )
    return violations