# Architecture guardrails for mooring — the dependency-direction rules from the
# migration plan, enforced by `uv run lint-imports` (in release CI beside ruff).
#
# The codebase has a clean implicit layering that the flat module namespace hides:
#
#   L4  cli, hub            the two presentation adapters
#   L3  ai/*                AI orchestration + privacy/safety
#   L2  sync/manifest/pbip/deletion (domain core) · editor/schema (marimo bridge)
#   L1  config/config_store/auth/github            identity + config
#   L0  githost/paths/gitsha                       stdlib-pure leaves
#
# These contracts lock that direction so a backwards import can't silently
# re-enter as the fast-moving ai/ subsystem keeps growing. They are intentionally
# a small, high-value set of `forbidden` rules (not a full strict layering) —
# each maps to a finding in the architecture review and passes today.
#
# As later migration phases land, contracts tighten. Phase 3 added runtime.py
# (a neutral L1 helper below both adapters) and removed the hub->cli edge; Phase 8
# added marimo_rt.py and the marimo-internals-isolated contract below (which needs
# include_external_packages so the forbidden marimo._*/urllib edges are seen).

[importlinter]
root_package = mooring
include_external_packages = True

[importlinter:contract:foundation-is-pure]
name = L0 foundation leaves import nothing else in mooring (stdlib-pure, callable at load time)
type = forbidden
source_modules =
    mooring.githost
    mooring.paths
    mooring.gitsha
forbidden_modules =
    mooring.config
    mooring.config_store
    mooring.auth
    mooring.github
    mooring.sync
    mooring.manifest
    mooring.pbip
    mooring.deletion
    mooring.editor
    mooring.pyproject_env
    mooring.schema
    mooring.ai
    mooring.hub
    mooring.cli
    mooring.telemetry

[importlinter:contract:identity-below-domain]
name = L1 config/identity/runtime/ai_config does not depend on the domain, AI, or the adapters
type = forbidden
source_modules =
    mooring.config
    mooring.config_store
    mooring.auth
    mooring.github
    mooring.runtime
    mooring.ai_config
forbidden_modules =
    mooring.sync
    mooring.manifest
    mooring.pbip
    mooring.deletion
    mooring.editor
    mooring.schema
    mooring.ai
    mooring.hub
    mooring.cli

[importlinter:contract:sync-domain-is-core]
name = L2 sync domain (the product core) does not depend on AI, the editor, or the adapters
type = forbidden
source_modules =
    mooring.sync
    mooring.manifest
    mooring.pbip
    mooring.deletion
forbidden_modules =
    mooring.ai
    mooring.editor
    mooring.hub
    mooring.cli

[importlinter:contract:ai-below-adapters]
name = L3 AI orchestration sits below the adapters and never imports the web hub or the CLI
type = forbidden
source_modules =
    mooring.ai
forbidden_modules =
    mooring.hub
    mooring.cli

[importlinter:contract:hub-not-cli]
name = The web hub and the CLI are sibling adapters; the hub must not import the CLI
type = forbidden
source_modules =
    mooring.hub
forbidden_modules =
    mooring.cli

[importlinter:contract:marimo-internals-isolated]
name = The ai/ layer touches neither marimo nor raw HTTP directly — both go through marimo_rt (the transport seam); editor.py keeps marimo's subprocess/.marimo.toml
type = forbidden
# import-linter can only forbid top-level external packages (not submodules), which
# is the right granularity here: ai/ must not import marimo (private codegen lives
# in marimo_rt) nor do its own HTTP control (urllib/http live in marimo_rt's
# KernelControl). marimo_rt and editor.py are not sources, so they keep access.
source_modules =
    mooring.ai
forbidden_modules =
    marimo
    urllib
    http
# Only DIRECT imports are forbidden: ai -> marimo_rt -> marimo (the legitimate path
# through the seam) is indirect and allowed; a NEW direct ai -> marimo/urllib import
# is the violation we want to catch.
allow_indirect_imports = True
