[importlinter]
root_packages =
    vibey
    vibey_gh
include_external_packages = True

[importlinter:contract:onion-layers]
name = Onion architecture layering
type = layers
layers =
    cli
    tui
    infrastructure
    application
    domain
containers =
    vibey


# Stdlib, itself, and any family package that is itself dependency-free (ADR-0017).
# `vibey-gh`, `vibey-skills` and `vibey-runners-common` all declare `dependencies = []`,
# so importing one adds nothing to the graph that stdlib-only did not already allow.
# `vibey_bootstrap` is named below for a stated reason rather than by category: it carries
# the Azure SDK and OpenTelemetry, so importing it here would pull a third-party graph in
# transitively and break the invariant by the back door. Use it from infrastructure/.
#
# `vibey.bootstrap` -- the composition root -- is named for a different reason: it sits
# outside the layer containers, so `onion-layers` does not reach it, and without this line
# the innermost layer could import the outermost module. A `forbidden` contract checks the
# source module's descendants, so this covers `vibey.domain.interfaces` too: an interface
# declares a seam and never imports the code that wires it (ADR-0016).
#
# The rest of the rule is not an import question at all -- no I/O, no async, no clock, no
# network -- and is enforced by tests/domain/test_domain_purity.py, which walks the AST.
[importlinter:contract:domain-independence]
name = domain imports stdlib, itself, and only dependency-free family packages
type = forbidden
source_modules =
    vibey.domain
forbidden_modules =
    vibey_bootstrap
    vibey.application
    vibey.infrastructure
    vibey.cli
    vibey.tui
    vibey.bootstrap
    asyncpg
    psycopg
    httpx
    typer
    structlog
    pydantic
    textual

[importlinter:contract:application-independence]
name = application does not import infrastructure, cli, or tui
type = forbidden
source_modules =
    vibey.application
forbidden_modules =
    vibey.infrastructure
    vibey.cli
    vibey.tui

# The interfaces packages are the bottom of their layer: they declare the
# seams, so they must never import the code that consumes them.
[importlinter:contract:interfaces-declare-only]
name = Interfaces declare seams, never consume them
type = forbidden
source_modules =
    vibey.application.interfaces
forbidden_modules =
    vibey.infrastructure
    vibey.cli
    vibey.tui
    vibey.bootstrap

# The same rule, one layer down. `vibey.infrastructure.db.interfaces` (ADR-0016's
# mirrored form) and the legacy flat `vibey.infrastructure.interfaces` declare seams
# that infrastructure itself implements, so the application contract's "nothing else
# from its own tree" clause cannot bind here: a seam over an asyncpg connection or a
# `LedgerEventDraft` has to name those types or it constrains nothing. What DOES bind
# is the direction -- a seam never reaches up into the code that consumes it.
# `vibey.infrastructure.engines.interfaces` joined with the sovereign DECOMPOSE
# producer and the shared Ollama client (#115).
[importlinter:contract:infrastructure-interfaces-declare-only]
name = Infrastructure interfaces declare seams, never consume them
type = forbidden
source_modules =
    vibey.infrastructure.interfaces
    vibey.infrastructure.db.interfaces
    vibey.infrastructure.engines.interfaces
forbidden_modules =
    vibey.cli
    vibey.tui
    vibey.bootstrap

# The same rule for the first `interfaces/` package in the absorbed vibey-gh (ADR-0016:
# tenants converge module by module, and a new module arrives with its seam declared).
[importlinter:contract:vibey-gh-interfaces-declare-only]
name = vibey_gh interfaces declare seams, never consume them
type = forbidden
source_modules =
    vibey_gh.interfaces
forbidden_modules =
    vibey_gh.cli
    vibey_gh.marketplace
    vibey_gh.documentation
    vibey_gh.fitloop
    vibey_gh.doctor
    vibey_gh.install
    vibey_gh.conversation
