Goal
Detect a port collision on the host pg port (5433 by default) BEFORE `docker compose up` fails, so the user gets an actionable hint instead of docker's terse "port is already allocated" error.
Sketch
```rust
fn probe_pg_port(port: u16) -> Result<()> {
match TcpStream::connect_timeout(&([127,0,0,1], port).into(), Duration::from_millis(200)) {
Ok() => Err(anyhow!(
"port {port} is already in use on localhost. Edit docker-compose.yml to change the host mapping (e.g. \"5434:5432\"), or stop whatever's using {port}."
)),
Err() => Ok(()),
}
}
```
Acceptance
- Conflict on 5433 surfaces a clear error message (no `docker compose up` output noise)
- No false positives from docker's own pg container (the probe runs BEFORE `compose up`)
- Skipped when `--no-compose` is set
Notes
This is the simplest version of port handling. Issue #28 (auto-port) supersedes this with auto-picking; ship this first as a low-risk improvement, replace later.
Goal
Detect a port collision on the host pg port (5433 by default) BEFORE `docker compose up` fails, so the user gets an actionable hint instead of docker's terse "port is already allocated" error.
Sketch
```rust
fn probe_pg_port(port: u16) -> Result<()> {
match TcpStream::connect_timeout(&([127,0,0,1], port).into(), Duration::from_millis(200)) {
Ok() => Err(anyhow!(
"port {port} is already in use on localhost. Edit docker-compose.yml to change the host mapping (e.g. \"5434:5432\"), or stop whatever's using {port}."
)),
Err() => Ok(()),
}
}
```
Acceptance
Notes
This is the simplest version of port handling. Issue #28 (auto-port) supersedes this with auto-picking; ship this first as a low-risk improvement, replace later.