Container tiering — backend-core is the application tier¶
Status¶
adopted-from-hub — the canonical decision is ARC-ADR-023 in the AgentArmy
hub (docs/decisions/ARC-ADR-023-container-tiering-strategy.md). This file is a
one-page shadow so a coding agent working in this spoke can see the rule
without leaving the repo.
Decision (as it applies here)¶
backend-core is the application tier. One container per spoke, stateless, rolling deploys. It does not own or ship platform-tier services.
Concretely:
image.json(root) declares"tier": "application".llm-gateway/image.jsondeclares"tier": "function"(the sibling small stateless gateway image).- No
image.jsonin this repo declares"tier": "platform". docker-compose.ymldoes not includearcadedata/*,postgres*,nats*, orstain/jena-fuseki*as services. Those are platform images and live in the hub'stemplates/local-stack/.- This spoke does not carry a platform
Dockerfile, Bicep template, or PowerShell deploy script outside the hub-syncedtemplates/paths. The ArcadeDB ACI Bicep +deploy/deploy.ps1that used to live here moved to the hub when ARC-ADR-023 landed.
backend-core reaches platform services over the network — the operator brings
the hub's local-stack up first, then docker compose up backend-core. The
connection URLs are env vars (ARCADEDB_URL, POSTGRES_URL, NATS_URL,
FUSEKI_URL).
Enforcement¶
The rule is enforced two ways:
- CLAUDE.md carries the rule under "Spoke-specific guidance" — the one place an AI coding agent reads before editing this repo.
- CI gate —
scripts/check_tier_separation.py(data-driven config atscripts/tier_separation.json) runs incontract-provider.yml'sdrift-and-validityjob. It fails on: - any
image:line indocker-compose.ymlmatching the platform-image denylist outside an allowlistedtemplates/path, - any
image.jsondeclaring"tier": "platform", - any
Dockerfile/setup.shunder a path named after a platform image (e.g.arcadedb-image/) outside hub-synced paths.
A self-test under tests/test_tier_separation.py proves the gate fires on a
bad fixture and stays silent on the good case — same pattern as the
.semgrep/no-persisted-credential.yml self-test in ci.yml.
What is not covered by this rule¶
- The
conformancejob incontract-provider.ymlmay spin up an ArcadeDB container as a CI service — that is an ephemeral test dependency, not a deploy, and is fine. - Issue #93 (collapsing backend-core's two application containers into one) is an application-tier consolidation and is complementary to this rule, not blocked by it.
Refs¶
- Hub: ARC-ADR-023 — container tiering + Platform Image Ownership amendment.
- PR #98 — removes vendored
templates/arcadedb-image/(first slice of cleanup). - Commits
4bc6546(function-tierllm-gateway) andb9509c5(application-tierimage.json+ doctor). templates/image-schema.json—tierenum:platform | application | function.