On a CI-managed host scripts/ci-deploy.sh owns port 3002 through the
blue/green slots, so a compose replica of the cms service could only ever
crash-loop on EADDRINUSE — it never serves traffic, because nginx points at a
slot container. Gate the service behind the `cms` profile so a bare
`docker compose up -d` starts only byparr. Naming the service explicitly
(`docker compose up -d cms`, which is what the installer and updater already
do) still enables the profile automatically, so the compose-only install path
keeps working.
Keep the one port that is actually served (3002) and make the 2 GB ceiling
hard by capping swap at 2g as well. Drop the green compose service (3003):
the green slot only ever exists as a docker run container created by CI, so
compose no longer defines it and the two paths cannot drift apart.
The loopback override contract stays covered: proxy-config.test.mjs now
renders the configuration with --profile cms, and a new build-contract test
pins the profile and the memory limits so neither can be dropped by accident.
- Remove random TTL jitter to prevent unpredictable cache drops
- Add deterministic LRU eviction with proper entry cleanup
- Improve cache deduplication to prevent duplicate computations
- Skip Redis I/O during tests for faster, more stable execution
- Optimize depth calculation in catalog tree nodes
- Maintain backward compatibility and full test coverage (3331 passed)