Skip to content

fix: make Board port binding multi-instance friendly - #545

Merged
jeffhuber merged 2 commits into
mainfrom
codex/v09-board-multi-instance-537
Sep 2, 2026
Merged

fix: make Board port binding multi-instance friendly#545
jeffhuber merged 2 commits into
mainfrom
codex/v09-board-multi-instance-537

Conversation

@jeffhuber

Copy link
Copy Markdown
Contributor

Summary

  • make board serve auto-select a nearby free loopback port when the default port is busy
  • keep explicit port selection strict with a friendly conflict message
  • document local URL scope and multi-instance behavior

Validation

  • scripts/dev-python -m unittest tests.test_board
  • scripts/dev-python -m ruff check src/code_mower/board.py tests/test_board.py
  • git diff --check
  • scripts/dev-python scripts/privacy_scan.py

Risk and rollback

Low. The change only affects local Board port binding. Roll back by reverting this PR; explicit ports remain deterministic.

Data and privacy

No cloud schema changes. Board remains loopback-only and local-first; docs keep the metadata-only/no source/diff/transcript boundary.

Closes #537. Part of #536.

@jeffhuber jeffhuber added builder:codex Code Mower generated label tier:R Code Mower generated label needs-claude-audit needs-gitar-audit Code Mower generated label labels Sep 2, 2026
Comment thread src/code_mower/board.py Outdated
Comment thread src/code_mower/board.py Outdated
@jeffhuber

Copy link
Copy Markdown
Contributor Author

Claude audit (merge-authority lane)

Head SHA: 47ddeb2d2ac562d32864de138ab878d648789c92
Findings: P0=0, P1=0, P2=0, P3=0 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

Board serve now falls forward to a nearby free loopback port only when --port was not explicitly supplied, while an explicit --port stays strict and reports a friendly conflict, matching the updated docs. Port validation, loopback enforcement, and the port-selection logic are correct, and new tests cover default fallback, explicit-port conflict, equals-form flag detection, and out-of-range port rejection. No correctness, security, or data-loss issues found.

Findings: none.

@gitar-bot

gitar-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown
Code Review ✅ Approved 2 resolved / 2 findings

Enables Board to auto-select a nearby free loopback port when the default port is busy, while keeping explicit port selection strict with a friendly conflict message and documenting local URL scope. Resolved abbreviated --port flag defeating the strict explicit-port contract and conflict suggestions exceeding the valid port range. No issues found.

✅ 2 resolved
Edge Case: Abbreviated --port flag defeats strict explicit-port contract

📄 src/code_mower/board.py:123-124 📄 src/code_mower/board.py:178 📄 src/code_mower/board.py:1110-1115
port_was_default is derived from _option_present(argv, "--port"), which only matches the exact --port/--port= token. argparse leaves allow_abbrev=True, so code-mower board serve --repo X --po 6000 (or --por) is accepted and sets args.port=6000, yet _option_present returns False. The port is then treated as the default and silently auto-falls-forward when busy — exactly the silent move the explicit-port path is meant to prevent. Detect the explicit port from parsed args rather than raw argv, e.g. add a distinct argparse default sentinel (default=None) for --port and set port_was_default = args.port is None, resolving the actual port afterward.

Quality: Explicit-port conflict suggestions can exceed 65535

📄 src/code_mower/board.py:141-146
In _bind_board_server, the friendly conflict message builds suggestions from range(port + 1, port + 4). For a high explicit port (e.g. --port 65534), this suggests 65535, 65536, 65537 — the latter two are invalid ports. Clamp the suggested candidates to <= 65535 (and omit the suffix entirely when none remain).

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@jeffhuber

Copy link
Copy Markdown
Contributor Author

Claude audit (merge-authority lane)

Head SHA: c12073e082f8e607d36d871bc0a404007f693716
Findings: P0=0, P1=0, P2=0, P3=1 (blocker policy: any P0/P1/P2 -> BLOCKED)

Claude Audit: PASS

Summary:

Board port-binding changes correctly implement the documented behavior: default port auto-falls-forward through a 10-port range on EADDRINUSE while an explicit --port stays strict and fails with a clear conflict message. Port validation, argparse wiring (--port default None -> port_was_default flag), and TCPServer's built-in socket cleanup on bind failure all check out. Tests cover the fallback, explicit-conflict, invalid-port, and abbreviated-flag paths. Docs (README, quickstart, data contract) are consistent with the implementation. No P0/P1/P2 issues found.

Findings:

  • [P3] Narrow auto-fallback port range -- src/code_mower/board.py:168
    Finding ID: claude:c459f3b004eec896a4b6
    _candidate_ports only tries 10 ports (config.port..config.port+9) when the default port is busy. In a dev environment with more than 10 concurrent Board instances, serve() will exit with a 'could not find a free loopback port' error instead of continuing to scan further. Non-blocking given the stated multi-instance use case is small-N local dev, but worth noting if the range should be configurable or wider.

@jeffhuber jeffhuber added claude-audit-done gitar-audit-done Code Mower generated label and removed needs-claude-audit needs-gitar-audit Code Mower generated label labels Sep 2, 2026
@jeffhuber
jeffhuber merged commit 533f8be into main Sep 2, 2026
23 checks passed
@jeffhuber
jeffhuber deleted the codex/v09-board-multi-instance-537 branch September 2, 2026 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

builder:codex Code Mower generated label claude-audit-done gitar-audit-done Code Mower generated label tier:R Code Mower generated label

Projects

None yet

Development

Successfully merging this pull request may close these issues.

v0.9: make Board serve multi-instance friendly

1 participant