# Import Linter configuration for Adapt
#
# Purpose:
# Enforce architectural boundaries so the codebase stays modular,
# testable, and free of accidental coupling.
#
# Run:
#   lint-imports
#
# Philosophy:
# - Modules are scientific units and must remain independent.
# - Shared behaviour belongs in contracts, runtime, or persistence.
# - Prevent cross-layer imports early, before they calcify.

[importlinter]
root_packages =
    adapt

include_external_packages = False

# ==========================================================
# 1. Scientific module independence — enforced by pytest
# ==========================================================
#
# Inter-module imports and upward imports from modules/ are
# caught by tests/test_architecture.py, which auto-discovers
# subpackages at runtime. No explicit module list needed there.
# Run: pytest tests/test_architecture.py


# ==========================================================
# 2. Modules do not depend on runtime orchestration
# ==========================================================
#
# Runtime coordinates modules; modules must not call back into it.
# Science is stateless. Orchestration is runtime's job.

[importlinter:contract:modules_do_not_import_runtime]
name = Modules do not depend on runtime
type = forbidden
source_modules =
    adapt.modules
forbidden_modules =
    adapt.runtime

# ==========================================================
# 3. Modules do not reach into infrastructure layers
# ==========================================================
#
# Modules produce data. Infrastructure stores and serves it.
# A module that imports persistence or GUI has too many responsibilities.
#
# Includes configuration: modules must receive their settings
# via dependency injection from the execution layer — not read
# configuration themselves.

[importlinter:contract:modules_do_not_import_infrastructure]
name = Modules do not import infrastructure layers
type = forbidden
source_modules =
    adapt.modules
forbidden_modules =
    adapt.execution
    adapt.persistence
    adapt.api
    adapt.gui
    adapt.visualization
    adapt.configuration

# ==========================================================
# 3b. Utils package imports no adapt internals
# ==========================================================
#
# adapt.utils contains pure stdlib functions shared across
# the codebase. It must not depend on any adapt layer or
# it creates import cycles and loses its zero-dependency value.

[importlinter:contract:utils_are_pure]
name = Utils package imports no adapt internals
type = forbidden
source_modules =
    adapt.utils
forbidden_modules =
    adapt.modules
    adapt.contracts
    adapt.execution
    adapt.runtime
    adapt.persistence
    adapt.configuration
    adapt.api
    adapt.gui
    adapt.visualization
    adapt.cli
    adapt.extensions

# ==========================================================
# 4. Persistence is infrastructure — no science, no orchestration
# ==========================================================
#
# Persistence reads and writes. It must not depend on modules
# (would create a circular science ↔ storage loop) or runtime
# (would couple storage to one execution strategy).

[importlinter:contract:persistence_is_infra]
name = Persistence does not depend on modules or runtime
type = forbidden
source_modules =
    adapt.persistence
forbidden_modules =
    adapt.modules
    adapt.runtime

# ==========================================================
# 5. Nothing inside core depends on the CLI
# ==========================================================
#
# CLI is the outermost shell. It may import anything.
# Core packages must not import it — that would make them
# impossible to use as a library.

[importlinter:contract:no_internal_cli_dependency]
name = Internal packages do not depend on CLI
type = forbidden
source_modules =
    adapt.modules
    adapt.runtime
    adapt.persistence
    adapt.execution
forbidden_modules =
    adapt.cli

# ==========================================================
# 6. Core must not depend on optional extensions
# ==========================================================
#
# Extensions add capability without modifying core.
# If core imports extensions, extensions can no longer be
# optional and the plug-in model breaks.

[importlinter:contract:core_not_depend_on_extensions]
name = Core packages do not depend on extensions
type = forbidden
source_modules =
    adapt.modules
    adapt.runtime
    adapt.persistence
    adapt.execution
    adapt.configuration
forbidden_modules =
    adapt.extensions

# ==========================================================
# 7. Contracts package imports no adapt internals
# ==========================================================
#
# adapt.contracts is the only layer both modules and execution
# may share. It must depend on nothing inside adapt so it
# never creates import cycles.

[importlinter:contract:contracts_are_pure]
name = Contracts package imports no adapt internals
type = forbidden
source_modules =
    adapt.contracts
forbidden_modules =
    adapt.modules
    adapt.runtime
    adapt.persistence
    adapt.configuration
    adapt.execution
    adapt.api
    adapt.gui
    adapt.visualization
    adapt.cli
    adapt.extensions
