Skip to content

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.