# CI Port Convention ## Reserved Range: 10000-10099 CI jobs never use production ports. Each service gets a fixed offset (1-99) within the 10000-10099 range. **Formula:** `CI_PORT = 10000 + CI_PORT_OFFSET` ## Port Assignments | Offset | CI Port | Service | |--------|---------|---------| | 1 | 10001 | NewsArchiverV2 | | 2 | 10002 | paste-bin | | 3-99 | 10003-10099 | Reserved for future services | ## Usage **CI workflow:** ```yaml docker run -d --name myapp-e2e \ --network test-network \ -e CI=true \ -e CI_PORT_OFFSET=1 \ myapp:test \ python main.py --serve --port 5000 # App auto-shifts to port 10001 ``` **App code (any service):** ```python if os.environ.get("CI") == "true" and os.environ.get("SKIP_PORT_SHIFT") != "1": offset = int(os.environ.get("CI_PORT_OFFSET", "1")) args.port = 10000 + offset print(f"[ci-port-shift] Port shifted from {original} to {args.port}") ``` **Production:** Never sets `CI=true` or `CI_PORT_OFFSET`. Ports stay unchanged. ## Rules 1. CI jobs always set `CI=true` and the service's `CI_PORT_OFFSET` 2. Port discovery via log parsing: `docker logs | grep "\[ci-port-shift\]"` 3. Container-to-container traffic uses Docker networks, never host port publish 4. Production containers never have `CI=true`