Orchestrata Ultimate › Gates › check-deps
Gate: check-deps
At a glance
| Purpose | Refuse a third-party import that pyproject.toml does not declare. |
| Where it runs | The scripts/gates.py battery (registered as check-deps); standalone from the AST toolkit. |
| Trigger | A battery run whose input fingerprint changed. |
| Exact command | python scripts/serialize_codebase_ast.py check-deps --include-tests |
| Blocks | Non-zero exit on any undeclared import; 0 when every third-party import is declared. |
| Ruling / ADR | None recorded; it mechanizes the CLAUDE.md Key Rule "Declare every dependency in pyproject.toml". |
| Last recorded verdict | ok: true in the primary checkout's .cache/gates.json (file last written 2026-09-22 10:01 local). wt-MAP-PRECOMMIT has no .cache/gates.json. |
What it refuses
A third-party Python import anywhere in the scanned trees that pyproject.toml does
not declare — code that works in the current venv but would break on a fresh
uv sync.
Why it exists
The project's Key Rule (CLAUDE.md): "Declare every dependency in pyproject.toml
— no undeclared/manually-installed packages; optional lazy-imported features go under
[project.optional-dependencies]. check-deps gates this." The implementation's
docstring (find_undeclared_dependencies in scripts/serialize_codebase_ast.py)
defines the two failure buckets:
- "
installed_undeclared— the import maps to an INSTALLED distribution that is absent from pyproject. A real reproducibility gap: it works in the current venv but a freshuv syncwould not install it."- "
missing_undeclared— imported, not stdlib / first-party / a local repo module, and NOT installed: an undeclared (often lazy/optional) third-party dependency, or an unresolved import to eyeball.""Clean imports (stdlib, first-party, local, or already declared) are omitted."
A single originating incident is not recorded in the source — origin not recorded in the source beyond the Key Rule it mechanizes.
How it runs
- Command:
python scripts/serialize_codebase_ast.py check-deps --include-tests(the battery's exact argv). The subcommand also accepts--source(comma-separated dirs, defaultsrc/orchestrata_ultimate),--pyproject, and--outputfor a JSON report. - When it fires: the
scripts/gates.pybattery (registered ascheck-deps); also runnable standalone (CLAUDE.md lists it in the AST-toolkit command set). - Inputs: fingerprint roots
_SRC = ("src", "scripts", "tests", "pyproject.toml")(theGATESentry inscripts/gates.py, read through the AST toolkit on 2026-10-23). An earlier version of this page listed a fifth root,claude, added "in the 2026-08-28 audit"; the registry onorigin/master(a4cbc2bdf) does not carry it, so aclaude/-only edit leaves this gate's cached PASS standing. - Caching: the verdict is cached in
.cache/gates.jsonagainst_fingerprint(roots): a sha256 over the relative path and bytes of every file under those roots whose suffix is.py,.toml,.pl,.json,.mdor.sh(_interesting(), which also skips__pycache__,.pytest_cache,.ruff_cache). There is no per-gate suffix mask: this page previously quoted aGATE_MASKStable, andgit log --all -S GATE_MASKS -- scripts/gates.pyfinds no commit that ever contained one (checked 2026-10-23).
Typical failures and how to fix them
- Exit code: non-zero on any undeclared import ("non-zero on gap", CLAUDE.md); 0 when every third-party import is declared.
- What a PASS looks like (real recorded battery output,
.cache/gates.json):25.0s | Dependency audit (59 declared deps): ✅ All third-party imports are declared in pyproject.toml. - What a failure looks like (representative): the audit names each offending
import with its bucket (
installed_undeclared/missing_undeclared) and the importing module. - Un-blocking:
uv add <package>(never pip — pip is blocked repo-wide), or move a lazy/optional import under[project.optional-dependencies]; for a first-party false positive, the local-module walk already excludes repo-local names.
Wiring
- Invokers:
scripts/gates.py(battery);scripts/health_check.pyinvokes the AST toolkit's check as part of its sweep (serialize_codebase_ast.pyappears in its battery list). - Enforcement siblings on the same registry: the banned-libraries list
.claude/banned-libraries.txtis enforced by test-purity's banned-import sweep, theno-banned-deps.shsession hook, and code-review's BANNED-DEP gate — check-deps covers the undeclared direction, those cover the forbidden one. - Tests:
tests/scripts/test_check_deps.py.
Related
- Gates master index
- Development workflow
- test-purity — the banned (forbidden) direction
- external-tools — "check-deps gates Python IMPORTS; it is structurally blind to a Go/Rust/C binary someone installed by hand" — that counterpart gate closes exactly that hole