Build: CMake with Conan for dependencies; a Debug build with sanitizers for development and
tests, a Release build for delivery.
Unit tests: Catch2, structured by GIVEN, WHEN, THEN.
Acceptance tests: pytest-bdd reads the scenarios from test/bdd/features/ and drives the
built binary. C++ has no maintained Gherkin runner of its own, and Behave cannot separate the
feature files from the step definitions.
Lint: clang-format and clang-tidy, whose naming and const-correctness checks fail the build.
Rationale: tests run against the Debug build, so sanitizers catch memory and undefined
behavior errors early; the Release build is tested again at merge to main.
Structure: layers app, infra, usecase, and domain; a health endpoint exercised by
liveness.feature; a domain model in specs/functional_design/domain_model.md.
Container image: built, scanned, and pushed in three jobs, handing the image over as an
archive, so a vulnerability scan can stop an image before it reaches the registry. The runtime
image is distroless: no shell and no package manager in production; a debug image adds
investigation tools.
Release: a release tag re-tags the image built and tested at merge to main; it is never
rebuilt.
Rationale: configuration comes from environment variables, so the same image runs in every
environment.
Debug and Release are built and tested against glibc and musl, catching libc incompatibilities
before they reach production; release jobs use the musl image.