580d8af7ae
Root cause: write_env_file used os.replace() which creates a new inode. Docker file bind-mounts track the original inode at mount time, so the container's /app/.env.compose never saw updates — docker compose always read the stale port value and skipped container recreation. Fixes: - ip_utils.write_env_file: write in-place (open 'w') instead of os.replace() so Docker bind-mounted files see the update immediately - apply_pending_config: add --force-recreate to docker compose up for specific-container restarts, bypassing config-hash comparison as a belt-and-suspenders measure Tests added: - TestWriteEnvFileInPlace: verifies inode is preserved across writes - TestApplyPendingConfigForceRecreate: verifies --force-recreate is in the docker compose command for specific-container restarts Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>