|
| 1 | +# FU-P7-T3-1 — Prioritize foreign port-owner guidance in mixed broker/dashboard conflicts |
| 2 | + |
| 3 | +## Objective Summary |
| 4 | + |
| 5 | +`P7-T3` removed the silent “broker alive, dashboard absent” partial state, but |
| 6 | +its review found one remaining mixed-state failure mode: when a broker PID is |
| 7 | +still live and the requested dashboard port is simultaneously occupied by a |
| 8 | +foreign listener, startup guidance prioritizes the broker reset path and can |
| 9 | +hide the actual port owner. That can send users into a reset loop while the |
| 10 | +real blocker, the unrelated listener on the port, remains untouched. |
| 11 | + |
| 12 | +This follow-up should make mixed-state diagnostics explicit across both startup |
| 13 | +and `--doctor`. The goal is not to invent a new recovery workflow. Instead, |
| 14 | +the code should surface the foreign port owner first or name both blockers in |
| 15 | +one clear remediation path, while preserving the existing single-listener and |
| 16 | +broker-without-dashboard behavior for non-mixed states. |
| 17 | + |
| 18 | +## Deliverables |
| 19 | + |
| 20 | +- Update `src/mcpbridge_wrapper/__main__.py` so mixed-state startup failures |
| 21 | + can report both a live broker PID and a foreign dashboard-port listener |
| 22 | + instead of hiding the listener behind broker-reset guidance. |
| 23 | +- Update `src/mcpbridge_wrapper/doctor.py` so mixed broker/listener conflicts |
| 24 | + classify as a port-ownership issue rather than the generic |
| 25 | + `broker-without-dashboard` diagnosis. |
| 26 | +- Add regression coverage in `tests/unit/test_main.py` and |
| 27 | + `tests/unit/test_doctor.py` for the mixed-state conflict path. |
| 28 | +- Produce `SPECS/INPROGRESS/FU-P7-T3-1_Validation_Report.md` with required |
| 29 | + quality-gate evidence. |
| 30 | + |
| 31 | +## Success Criteria |
| 32 | + |
| 33 | +- `--broker-console` and `--broker-daemon --web-ui` mention the foreign |
| 34 | + dashboard-port listener or both blockers when a live broker PID and foreign |
| 35 | + listener coexist. |
| 36 | +- `--doctor` no longer hides the foreign listener behind a generic |
| 37 | + broker-without-dashboard diagnosis in the same mixed state. |
| 38 | +- Regression tests pin the mixed-state ordering so future changes cannot revert |
| 39 | + to broker-only guidance. |
| 40 | + |
| 41 | +## Test-First Plan |
| 42 | + |
| 43 | +1. Add startup tests that model the mixed state for both `_run_broker_console()` |
| 44 | + and `main()`’s `--broker-daemon --web-ui` path, asserting the foreign port |
| 45 | + owner is surfaced alongside the live broker PID. |
| 46 | +2. Add a doctor-classification test for a live local broker plus foreign |
| 47 | + listener on the configured dashboard port, asserting the report stays in the |
| 48 | + port-occupied family instead of `broker-without-dashboard`. |
| 49 | +3. Implement the smallest production changes needed to collect both blockers |
| 50 | + before choosing the user-facing guidance path. |
| 51 | +4. Run the required quality gates: `pytest`, `ruff check src/`, `mypy src/`, |
| 52 | + and `pytest --cov`. |
| 53 | + |
| 54 | +## Execution Plan |
| 55 | + |
| 56 | +### Phase 1: Pin the mixed-state startup contract |
| 57 | + |
| 58 | +Inputs: |
| 59 | +- `src/mcpbridge_wrapper/__main__.py` |
| 60 | +- existing `P7-T3` startup tests in `tests/unit/test_main.py` |
| 61 | + |
| 62 | +Outputs: |
| 63 | +- regression tests for mixed-state broker PID + foreign listener conflicts |
| 64 | +- a precise expected stderr contract for broker-console and broker-daemon flows |
| 65 | + |
| 66 | +Verification: |
| 67 | +- the new startup tests fail on the current ordering that hides the foreign |
| 68 | + listener |
| 69 | + |
| 70 | +### Phase 2: Align startup guidance |
| 71 | + |
| 72 | +Inputs: |
| 73 | +- `_run_broker_console()` |
| 74 | +- `_report_requested_dashboard_unavailable()` |
| 75 | +- broker-daemon web-ui startup branch in `main()` |
| 76 | + |
| 77 | +Outputs: |
| 78 | +- startup logic that can see both `running_broker_pid` and `listener_pids` |
| 79 | +- one explicit remediation path that surfaces the foreign listener without |
| 80 | + dropping broker-state context |
| 81 | + |
| 82 | +Verification: |
| 83 | +- startup messaging for single-blocker states remains unchanged |
| 84 | +- mixed-state messaging mentions the foreign listener or both blockers |
| 85 | + |
| 86 | +### Phase 3: Align doctor classification and validate |
| 87 | + |
| 88 | +Inputs: |
| 89 | +- `src/mcpbridge_wrapper/doctor.py` |
| 90 | +- doctor classification tests |
| 91 | +- full repo quality gates |
| 92 | + |
| 93 | +Outputs: |
| 94 | +- mixed-state doctor report that stays actionable and consistent with startup |
| 95 | +- validation report with targeted and full quality-gate evidence |
| 96 | + |
| 97 | +Verification: |
| 98 | +- `--doctor` and startup both direct the user toward resolving the foreign port |
| 99 | + conflict before or alongside broker reset |
| 100 | +- coverage remains at or above the repository threshold |
| 101 | + |
| 102 | +## Acceptance Tests |
| 103 | + |
| 104 | +- `pytest tests/unit/test_main.py` |
| 105 | +- `pytest tests/unit/test_doctor.py` |
| 106 | +- `pytest` |
| 107 | +- `ruff check src/` |
| 108 | +- `mypy src/` |
| 109 | +- `pytest --cov` |
| 110 | + |
| 111 | +## Decision Points |
| 112 | + |
| 113 | +- Prefer a combined-message approach when both blockers are real; users should |
| 114 | + not lose visibility into the live broker PID just because the foreign |
| 115 | + listener is now prioritized. |
| 116 | +- Keep the public recovery commands aligned with `P7-T3` and `P7-T2` rather |
| 117 | + than inventing a new remediation surface for this follow-up. |
| 118 | + |
| 119 | +## Notes |
| 120 | + |
| 121 | +- No documentation changes are expected unless the implementation forces |
| 122 | + observable command/help text changes beyond stderr diagnostics. |
| 123 | +- Review subject name for this task: `mixed_dashboard_conflict_guidance`. |
| 124 | + |
| 125 | +--- |
| 126 | +**Archived:** 2026-03-07 |
| 127 | +**Verdict:** PASS |
0 commit comments