ADR-005: Pinned dependencies and resource-bounded services
Status: accepted · Date: 2026-09-10
Context
Reproducible handoff requires Luna to install the same dependency graph and start the same services. Floating tags and a monolithic image make failures difficult to attribute.
Decision
Use Python 3.12, uv, exact versions in pyproject.toml and uv.lock, and separate inference dependency group. The artifact image excludes PyTorch. Compose uses the verified Neo4j Community 2025.09.0-community Apple Silicon digest, 2 CPUs/4 GiB, 1–2 GiB heap, and 1 GiB page cache; artifacts use 1 CPU/1 GiB. Secrets are files excluded from Git.
Mechanics and tests
Run uv lock, uv sync --all-groups, docker compose config, health checks, and a smoke upload. Record OS, Swift, image digest, package lock hash, and model revisions in every evaluation run. Upgrade by an ADR update and fixture/regression run.
Consequences
Pins age and require maintenance. The split keeps the small service image reliable and host inference flexible. Revisit when measured corpus size or deployment target requires a vector database or distributed graph.
Alternatives considered
Unpinned dependencies were rejected because a handoff could silently change parser or model behavior. A single image containing PyTorch was rejected because the artifact API does not need a multi-gigabyte inference stack. Floating container tags were rejected because an image update can alter Neo4j behavior without a source change.
Implementation detail and example
Runtime dependencies are exact-pinned in pyproject.toml and resolved in uv.lock; inference, development, and reporting dependencies are separate groups. The artifact image installs only its service requirements and pins the python:3.12.10-slim arm64 digest. Compose names volumes deadwire_artifacts, deadwire_state, deadwire_neo4j_data, and deadwire_logs, and uses loopback bindings, health checks, restart policy, Docker-internal read-only secret volumes prepared from owner-only host files, and bounded JSON log rotation.
Configuration and failure behavior
The version matrix records Python 3.12, Swift 6.3.3, the Docker/Compose version, Neo4j Community 2025.09.0-community, both image digests, and the exact host model identifiers. uv lock or a container pull failure stops setup; Luna must resolve the lock or update this ADR and rerun fixtures rather than choosing latest. A full artifact or log volume is an operational failure requiring the documented backup/restore runbook.
Verification and revisit trigger
Run uv sync --all-groups, uv lock --check, docker compose config --quiet, health checks, and an authenticated idempotent artifact upload. Revisit pins only with a recorded changelog, lock diff, image digest, and regression/evaluation result for the affected stage.