|
| 1 | +# P7-T3 — Auto-recover or guide on dashboard port ownership conflicts |
| 2 | + |
| 3 | +## Objective Summary |
| 4 | + |
| 5 | +`P7-T1` introduced the explicit dedicated-host workflow and `P7-T2` gave users |
| 6 | +one-command diagnostics, but the most confusing failure mode is still in the |
| 7 | +startup path itself: `--broker-daemon --web-ui` can leave a running broker |
| 8 | +behind while silently skipping the dashboard whenever the desired port is |
| 9 | +occupied. That produces a partial state where the recommended frontend is down, |
| 10 | +TUI cannot attach, and the user is forced to reason about multiple black boxes |
| 11 | +at once. |
| 12 | + |
| 13 | +`P7-T3` should remove that ambiguity. When users request the broker-hosted |
| 14 | +dashboard, startup must either recover deterministically into a usable state or |
| 15 | +stop with one explicit remediation path. The implementation should align |
| 16 | +broker-daemon startup, broker-console orchestration, doctor messaging, and TUI |
| 17 | +feedback around the same model so the user is never told that a degraded |
| 18 | +dashboard-less host is “good enough”. |
| 19 | + |
| 20 | +## Deliverables |
| 21 | + |
| 22 | +- Tighten the broker-daemon startup path in |
| 23 | + `src/mcpbridge_wrapper/__main__.py` so an explicit `--web-ui` request does not |
| 24 | + silently degrade into “broker without dashboard”. |
| 25 | +- Add shared logic that classifies dashboard port conflicts into actionable |
| 26 | + buckets: |
| 27 | + - healthy broker-backed dashboard already serving the port |
| 28 | + - foreign or stale listener on the desired port |
| 29 | + - local broker already running without dashboard on the desired port |
| 30 | + - restart-eligible wrapper-owned listener when `--web-ui-restart` is used |
| 31 | +- Update user-facing messaging so the failing command prints one clear next |
| 32 | + action instead of continuing in a partial state. |
| 33 | +- Extend doctor/TUI-facing guidance where needed so conflict explanations and |
| 34 | + remediation text stay consistent with the startup behavior. |
| 35 | +- Add regression tests for broker-daemon, broker-console, and diagnostics |
| 36 | + scenarios that previously stranded users. |
| 37 | + |
| 38 | +## Success Criteria |
| 39 | + |
| 40 | +- `mcpbridge-wrapper --broker-daemon --web-ui` no longer leaves a healthy-seeming |
| 41 | + broker running without the requested dashboard when the port cannot be used. |
| 42 | +- Port conflicts resolve into one of two outcomes only: |
| 43 | + - the requested broker-backed dashboard becomes available, or |
| 44 | + - the command exits non-zero with an explicit remediation path |
| 45 | +- `--broker-console` and `--doctor` surface the same conflict class and |
| 46 | + recommended next action for the same runtime state. |
| 47 | +- Tests pin both safe recovery and fail-fast behavior so future changes do not |
| 48 | + reintroduce the hidden partial state. |
| 49 | + |
| 50 | +## Test-First Plan |
| 51 | + |
| 52 | +1. Add broker-daemon CLI tests that lock in the new fail-fast behavior when |
| 53 | + `--web-ui` is requested but the target port is occupied by a foreign |
| 54 | + listener, stale listener, or unusable existing runtime. |
| 55 | +2. Add orchestration tests for `--broker-console` that verify it reuses a |
| 56 | + healthy broker-backed dashboard, restarts only when explicitly permitted, and |
| 57 | + reports a single remediation path for foreign ownership conflicts. |
| 58 | +3. Add doctor classification/rendering tests for the updated conflict buckets so |
| 59 | + diagnostics remain aligned with the startup behavior. |
| 60 | +4. Only after the new expectations are pinned, implement the shared conflict |
| 61 | + classifier and wire it into the daemon startup/orchestration flow. |
| 62 | +5. Run required quality gates: `pytest`, `ruff check src/`, `mypy src/`, and |
| 63 | + `pytest --cov`. |
| 64 | + |
| 65 | +## Execution Plan |
| 66 | + |
| 67 | +### Phase 1: Define the startup contract |
| 68 | + |
| 69 | +Inputs: |
| 70 | +- `src/mcpbridge_wrapper/__main__.py` |
| 71 | +- existing broker-console/dashboard probe helpers |
| 72 | +- `src/mcpbridge_wrapper/doctor.py` |
| 73 | + |
| 74 | +Outputs: |
| 75 | +- a clear contract for what counts as “dashboard ready” |
| 76 | +- shared conflict categories for healthy reuse, recoverable ownership, and |
| 77 | + explicit remediation |
| 78 | +- deterministic stderr wording for broker-daemon and broker-console entrypoints |
| 79 | + |
| 80 | +Verification: |
| 81 | +- every dashboard startup branch ends in either usable dashboard availability or |
| 82 | + non-zero failure |
| 83 | +- no code path continues with `--web-ui` requested after a port conflict unless |
| 84 | + the dashboard is actually reachable |
| 85 | + |
| 86 | +### Phase 2: Implement shared conflict handling |
| 87 | + |
| 88 | +Inputs: |
| 89 | +- dashboard port probes and listener ownership helpers |
| 90 | +- broker PID/socket/version state |
| 91 | +- existing `/api/control` and `/api/broker/status` probes |
| 92 | + |
| 93 | +Outputs: |
| 94 | +- reusable conflict-resolution helper(s) for broker startup/orchestration |
| 95 | +- explicit reuse path for already-healthy broker-backed dashboards |
| 96 | +- fail-fast or restart-assisted path for foreign/stale ownership conflicts |
| 97 | + |
| 98 | +Verification: |
| 99 | +- running broker + healthy dashboard remains a no-op/reuse case |
| 100 | +- foreign listeners and broker-without-dashboard states do not continue as |
| 101 | + “success” |
| 102 | + |
| 103 | +### Phase 3: Align diagnostics and finalize validation |
| 104 | + |
| 105 | +Inputs: |
| 106 | +- shared conflict results from startup/orchestration |
| 107 | +- doctor and TUI user guidance |
| 108 | +- unit and integration tests covering startup/diagnostic flows |
| 109 | + |
| 110 | +Outputs: |
| 111 | +- aligned doctor guidance for port ownership conflicts |
| 112 | +- regression tests across broker-daemon, broker-console, and doctor |
| 113 | +- validation report with required quality-gate output |
| 114 | + |
| 115 | +Verification: |
| 116 | +- the same runtime state yields the same diagnosis and remediation whether users |
| 117 | + encounter it during startup, in TUI, or via `--doctor` |
| 118 | +- no existing broker/web-ui/TUI entrypoints regress |
| 119 | + |
| 120 | +## Acceptance Tests |
| 121 | + |
| 122 | +- `pytest tests/unit/test_main.py` |
| 123 | +- `pytest tests/unit/test_main_tui.py` |
| 124 | +- `pytest tests/unit/test_doctor.py` |
| 125 | +- `pytest tests/unit/test_tui.py` |
| 126 | +- `pytest` |
| 127 | +- `ruff check src/` |
| 128 | +- `mypy src/` |
| 129 | +- `pytest --cov` |
| 130 | + |
| 131 | +## Decision Points |
| 132 | + |
| 133 | +- Prefer fail-fast over silent degradation for explicit `--web-ui` requests; a |
| 134 | + running broker without the requested dashboard is a broken UX state, not a |
| 135 | + successful startup. |
| 136 | +- Reuse the existing dashboard probe surfaces instead of inventing a second |
| 137 | + ownership model just for startup recovery. |
| 138 | +- Keep automatic recovery narrowly scoped to deterministic wrapper-owned cases; |
| 139 | + otherwise print one clear remediation path and exit. |
| 140 | + |
| 141 | +## Notes |
| 142 | + |
| 143 | +- If implementation exposes common conflict helpers that both `doctor.py` and |
| 144 | + `__main__.py` should consume, prefer that refactor now over duplicating |
| 145 | + ownership logic again. |
| 146 | +- The dedicated-host workflow introduced in `P7-T1` remains the product path; |
| 147 | + messaging should continue to steer users toward `--broker-console` or |
| 148 | + `--broker-daemon --web-ui`, not ad-hoc manual recovery. |
| 149 | +- Review subject name for this task: `dashboard_port_ownership_conflicts`. |
| 150 | + |
| 151 | +--- |
| 152 | +**Archived:** 2026-03-07 |
| 153 | +**Verdict:** PASS |
0 commit comments