Goal
`mirrorstack dev --auto-port` (or `--auto`) picks free ports for both the bundled pg and the module's HTTP listener at startup, then sends the chosen `local_url` to dispatch in the WSS `register` frame so Leaf 1 routing always 302s to the correct port — even when ports shift between runs.
This is the runtime-flexible cousin of #27 (which only fixes the scaffold-time default). #27 nicens the first run; #28 makes every run port-collision-proof.
Why this matters
Currently `--local-url` is a static flag (`http://localhost:8080\` default). If port 8080 is taken at `dev` startup, the SDK fails to bind. Even if we solve that, the registered URL goes stale across runs. With `--auto-port`:
- pg port: scan upward from 5433, write the chosen one into compose + `MS_LOCAL_DB_URL`
- module port: scan upward from 8080, set via `MS_HTTP_PORT` (env the SDK already reads, OR a new env we add)
- `local_url` for the register frame: built from the chosen module port (`http://localhost:`)
- Tunnel session carries the dynamic URL → dispatch's Leaf 1 302s to it correctly
Sketch
```rust
let pg_port = pick_free_port(5433)?;
let app_port = pick_free_port(8080)?;
let local_url = format!("http://localhost:{app_port}\");
// Render compose with chosen pg_port (re-bootstrap or in-memory only)
// Set MS_HTTP_PORT=<app_port> when spawning go run .
// Pass local_url to tunnel::open(... register: RegisterPayload { local_url: &local_url, ... })
```
Open questions
- Compose file: re-bootstrap with new port, or use `docker compose up` with a port override env? Override is less surprising (devs may have edited their compose).
- Module port: does the SDK honor `MS_HTTP_PORT` already, or do we need a new env / a new wiring?
- Re-registration: if `--auto-port` shifts between runs, does the platform see two stale registrations? Sessions store TTL is 24h, so until #69 (or whatever shipped Phase 1's session lifecycle), there's drift. Probably fine — old registration just expires.
Deps
Acceptance
- `mirrorstack dev --auto-port` scans pg + module ports, surfaces them in startup output ("pg :5434, module :8081")
- WSS register frame carries the chosen `local_url` (verifiable on the dispatch side once #113-116 + IaC ship)
- Browser hit to `/m/<module_id>/foo` 302s to the correct localhost port
Estimate
~120 LoC. Mostly straightforward; the SDK port wiring is the one unknown.
Goal
`mirrorstack dev --auto-port` (or `--auto`) picks free ports for both the bundled pg and the module's HTTP listener at startup, then sends the chosen `local_url` to dispatch in the WSS `register` frame so Leaf 1 routing always 302s to the correct port — even when ports shift between runs.
This is the runtime-flexible cousin of #27 (which only fixes the scaffold-time default). #27 nicens the first run; #28 makes every run port-collision-proof.
Why this matters
Currently `--local-url` is a static flag (`http://localhost:8080\` default). If port 8080 is taken at `dev` startup, the SDK fails to bind. Even if we solve that, the registered URL goes stale across runs. With `--auto-port`:
Sketch
```rust
let pg_port = pick_free_port(5433)?;
let app_port = pick_free_port(8080)?;
let local_url = format!("http://localhost:{app_port}\");
// Render compose with chosen pg_port (re-bootstrap or in-memory only)
// Set MS_HTTP_PORT=<app_port> when spawning go run .
// Pass local_url to tunnel::open(... register: RegisterPayload { local_url: &local_url, ... })
```
Open questions
Deps
Acceptance
Estimate
~120 LoC. Mostly straightforward; the SDK port wiring is the one unknown.